From 29cd838eab01ed7110f3ccb2e8c6a35c8a31dbcc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:21:29 +0200 Subject: Adding upstream version 1:0.1.9998svn3589+dfsg. Signed-off-by: Daniel Baumann --- src/kmk/.gitignore | 62 + src/kmk/.purify | 12 + src/kmk/AUTHORS | 88 + src/kmk/COPYING | 674 ++ src/kmk/ChangeLog.1 | 4997 ++++++++++++ src/kmk/ChangeLog.2 | 6653 ++++++++++++++++ src/kmk/ChangeLog.3 | 5633 +++++++++++++ src/kmk/INSTALL | 231 + src/kmk/Makefile.DOS.template | 587 ++ src/kmk/Makefile.am | 333 + src/kmk/Makefile.ami | 308 + src/kmk/Makefile.kmk | 770 ++ src/kmk/Makefile.os2 | 47 + src/kmk/NEWS | 1540 ++++ src/kmk/NMakefile.template | 132 + src/kmk/README.Amiga | 77 + src/kmk/README.DOS.template | 340 + src/kmk/README.OS2.template | 176 + src/kmk/README.VMS | 515 ++ src/kmk/README.W32.template | 314 + src/kmk/README.customs | 112 + src/kmk/README.git | 292 + src/kmk/README.template | 178 + src/kmk/SCOPTIONS | 13 + src/kmk/SMakefile.template | 218 + src/kmk/TODO.private | 117 + src/kmk/acinclude.m4 | 163 + src/kmk/alloca.c | 503 ++ src/kmk/alloccache.c | 259 + src/kmk/amiga.c | 117 + src/kmk/amiga.h | 18 + src/kmk/ar.c | 328 + src/kmk/arscan.c | 982 +++ src/kmk/build.template | 81 + src/kmk/build_w32.bat | 250 + src/kmk/commands.c | 954 +++ src/kmk/commands.h | 70 + src/kmk/config.ami.template | 337 + src/kmk/config.h-vms.template | 432 + src/kmk/config.h.W32.template | 532 ++ src/kmk/config.h.darwin | 491 ++ src/kmk/config.h.freebsd | 433 + src/kmk/config.h.haiku | 459 ++ src/kmk/config.h.linux | 498 ++ src/kmk/config.h.netbsd | 459 ++ src/kmk/config.h.os2 | 476 ++ src/kmk/config.h.solaris | 443 ++ src/kmk/config.h.win | 575 ++ src/kmk/config/.gitignore | 12 + src/kmk/config/ChangeLog.1 | 49 + src/kmk/config/Makefile.am | 18 + src/kmk/config/dospaths.m4 | 33 + src/kmk/configh.dos.template | 113 + src/kmk/configure.ac | 534 ++ src/kmk/configure.bat | 60 + src/kmk/debug.h | 66 + src/kmk/default.c | 774 ++ src/kmk/dep.h | 184 + src/kmk/dir-nt-bird.c | 794 ++ src/kmk/dir.c | 1602 ++++ src/kmk/doc/.gitignore | 22 + src/kmk/doc/Makefile.am | 24 + src/kmk/dosbuild.bat | 65 + src/kmk/electric.c | 220 + src/kmk/electric.h | 66 + src/kmk/example-spaces.kmk | 175 + src/kmk/expand.c | 1286 +++ src/kmk/expreval.c | 2387 ++++++ src/kmk/file.c | 1458 ++++ src/kmk/filedef.h | 254 + src/kmk/function.c | 8250 ++++++++++++++++++++ src/kmk/getloadavg.c | 1026 +++ src/kmk/getopt.c | 1031 +++ src/kmk/getopt.h | 132 + src/kmk/getopt1.c | 176 + src/kmk/gettext.h | 57 + src/kmk/glob/COPYING.LIB | 481 ++ src/kmk/glob/ChangeLog | 191 + src/kmk/glob/Makefile.am | 30 + src/kmk/glob/Makefile.ami | 67 + src/kmk/glob/SCOPTIONS | 13 + src/kmk/glob/SMakefile | 67 + src/kmk/glob/configure.bat | 43 + src/kmk/glob/fnmatch.c | 489 ++ src/kmk/glob/fnmatch.h | 85 + src/kmk/glob/glob.c | 1463 ++++ src/kmk/glob/glob.h | 215 + src/kmk/gmk-default.scm | 53 + src/kmk/gnumake.h | 79 + src/kmk/guile.c | 159 + src/kmk/hash.c | 536 ++ src/kmk/hash.h | 251 + src/kmk/implicit.c | 1011 +++ src/kmk/incdep.c | 2250 ++++++ src/kmk/inlined_memchr.h | 162 + src/kmk/job.c | 3991 ++++++++++ src/kmk/job.h | 175 + src/kmk/kbuild-object.c | 1409 ++++ src/kmk/kbuild.c | 3030 +++++++ src/kmk/kbuild.h | 77 + src/kmk/kbuildprf.c | 49 + src/kmk/kdepdb.c | 1087 +++ src/kmk/kmk_cc_exec.c | 7613 ++++++++++++++++++ src/kmk/kmk_cc_exec.h | 48 + src/kmk/kmkbuiltin.c | 507 ++ src/kmk/kmkbuiltin.h | 184 + src/kmk/kmkbuiltin/Makefile.kup | 0 src/kmk/kmkbuiltin/append.c | 459 ++ src/kmk/kmkbuiltin/cat.c | 416 + src/kmk/kmkbuiltin/chmod.c | 288 + src/kmk/kmkbuiltin/cmp.c | 153 + src/kmk/kmkbuiltin/cmp_extern.h | 49 + src/kmk/kmkbuiltin/cmp_util.c | 562 ++ src/kmk/kmkbuiltin/common-env-and-cwd-opt.c | 516 ++ src/kmk/kmkbuiltin/cp.c | 779 ++ src/kmk/kmkbuiltin/cp_extern.h | 55 + src/kmk/kmkbuiltin/cp_utils.c | 397 + src/kmk/kmkbuiltin/darwin.c | 55 + src/kmk/kmkbuiltin/echo.c | 125 + src/kmk/kmkbuiltin/err.c | 340 + src/kmk/kmkbuiltin/err.h | 38 + src/kmk/kmkbuiltin/expr.c | 617 ++ src/kmk/kmkbuiltin/fts.c | 1461 ++++ src/kmk/kmkbuiltin/ftsfake.h | 159 + src/kmk/kmkbuiltin/getopt1_r.c | 186 + src/kmk/kmkbuiltin/getopt_r.c | 1090 +++ src/kmk/kmkbuiltin/getopt_r.h | 182 + src/kmk/kmkbuiltin/haikufakes.c | 53 + src/kmk/kmkbuiltin/haikufakes.h | 42 + src/kmk/kmkbuiltin/install.c | 1248 +++ src/kmk/kmkbuiltin/kDepIDB.c | 860 ++ src/kmk/kmkbuiltin/kDepObj.c | 1250 +++ src/kmk/kmkbuiltin/kSubmit.c | 2116 +++++ src/kmk/kmkbuiltin/kbuild_protection.c | 376 + src/kmk/kmkbuiltin/kbuild_protection.h | 67 + src/kmk/kmkbuiltin/kill.c | 653 ++ src/kmk/kmkbuiltin/ln.c | 287 + src/kmk/kmkbuiltin/md5sum.c | 874 +++ src/kmk/kmkbuiltin/mkdir.c | 302 + src/kmk/kmkbuiltin/mscfakes.c | 839 ++ src/kmk/kmkbuiltin/mscfakes.h | 183 + src/kmk/kmkbuiltin/mv.c | 529 ++ src/kmk/kmkbuiltin/openbsd.c | 54 + src/kmk/kmkbuiltin/osdep.c | 48 + src/kmk/kmkbuiltin/printf.c | 954 +++ src/kmk/kmkbuiltin/redirect.c | 2066 +++++ src/kmk/kmkbuiltin/rm.c | 844 ++ src/kmk/kmkbuiltin/rmdir.c | 251 + src/kmk/kmkbuiltin/setmode.c | 506 ++ src/kmk/kmkbuiltin/sleep.c | 179 + src/kmk/kmkbuiltin/solfakes.c | 99 + src/kmk/kmkbuiltin/solfakes.h | 51 + src/kmk/kmkbuiltin/strlcpy.c | 78 + src/kmk/kmkbuiltin/strmode.c | 197 + src/kmk/kmkbuiltin/test.c | 869 +++ src/kmk/kmkbuiltin/touch.c | 952 +++ src/kmk/load.c | 267 + src/kmk/loadapi.c | 82 + src/kmk/main.c | 4482 +++++++++++ src/kmk/maintMakefile | 414 + src/kmk/make.1 | 381 + src/kmk/make.lnk | 5 + src/kmk/make_msvc_net2003.sln | 21 + src/kmk/make_msvc_net2003.vcproj | 340 + src/kmk/makefile.com | 166 + src/kmk/makefile.vms | 180 + src/kmk/makeint.h | 1195 +++ src/kmk/misc.c | 1358 ++++ src/kmk/os.h | 84 + src/kmk/output.c | 1392 ++++ src/kmk/output.h | 107 + src/kmk/po/.gitignore | 15 + src/kmk/po/LINGUAS | 5 + src/kmk/po/Makevars | 59 + src/kmk/po/POTFILES.in | 48 + src/kmk/posixos.c | 480 ++ src/kmk/prepare_vms.com | 59 + src/kmk/prepare_w32.bat | 6 + src/kmk/read.c | 4101 ++++++++++ src/kmk/remake.c | 2124 +++++ src/kmk/remote-cstms.c | 300 + src/kmk/remote-stub.c | 99 + src/kmk/rule.c | 546 ++ src/kmk/rule.h | 58 + src/kmk/signame.c | 254 + src/kmk/strcache.c | 368 + src/kmk/strcache2.c | 1327 ++++ src/kmk/strcache2.h | 182 + src/kmk/subproc.bat | 24 + src/kmk/testcase-2ndtargetexp.kmk | 68 + src/kmk/testcase-assignments.kmk | 29 + src/kmk/testcase-if1of.kmk | 80 + src/kmk/testcase-ifeq-escape.kmk | 18 + src/kmk/testcase-includedep-esc-sub.kmk | 113 + src/kmk/testcase-includedep-esc.kmk | 133 + src/kmk/testcase-includedep-sub.kmk | 28 + src/kmk/testcase-includedep.kmk | 90 + src/kmk/testcase-kBuild-define.kmk | 141 + src/kmk/testcase-lazy-deps-vars.kmk | 72 + src/kmk/testcase-libpath.kmk | 20 + src/kmk/testcase-local.kmk | 127 + src/kmk/testcase-math.kmk | 98 + src/kmk/testcase-root.kmk | 30 + src/kmk/testcase-stack.kmk | 86 + src/kmk/testcase-which.kmk | 5 + src/kmk/testcase-xargs.kmk | 59 + src/kmk/testcase/testcase-export.kmk | 48 + src/kmk/tests/.gitignore | 2 + src/kmk/tests/COPYING | 674 ++ src/kmk/tests/ChangeLog.1 | 1429 ++++ src/kmk/tests/NEWS | 178 + src/kmk/tests/README | 102 + src/kmk/tests/config-flags.pm.in | 19 + src/kmk/tests/config_flags_pm.com | 53 + src/kmk/tests/guile.supp | 31 + src/kmk/tests/mkshadow | 57 + src/kmk/tests/run_make_tests | 2 + src/kmk/tests/run_make_tests.com | 272 + src/kmk/tests/run_make_tests.pl | 507 ++ src/kmk/tests/scripts/features/archives | 213 + src/kmk/tests/scripts/features/comments | 35 + src/kmk/tests/scripts/features/conditionals | 162 + src/kmk/tests/scripts/features/default_names | 44 + src/kmk/tests/scripts/features/double_colon | 220 + src/kmk/tests/scripts/features/echoing | 64 + src/kmk/tests/scripts/features/errors | 107 + src/kmk/tests/scripts/features/escape | 74 + src/kmk/tests/scripts/features/export | 186 + src/kmk/tests/scripts/features/ifcond | 950 +++ src/kmk/tests/scripts/features/include | 243 + src/kmk/tests/scripts/features/jobserver | 107 + src/kmk/tests/scripts/features/load | 110 + src/kmk/tests/scripts/features/loadapi | 116 + src/kmk/tests/scripts/features/mult_rules | 78 + src/kmk/tests/scripts/features/mult_targets | 46 + src/kmk/tests/scripts/features/order_only | 118 + src/kmk/tests/scripts/features/output-sync | 349 + src/kmk/tests/scripts/features/override | 45 + src/kmk/tests/scripts/features/parallelism | 231 + src/kmk/tests/scripts/features/patspecific_vars | 148 + src/kmk/tests/scripts/features/patternrules | 232 + src/kmk/tests/scripts/features/quoting | 32 + src/kmk/tests/scripts/features/recursion | 55 + src/kmk/tests/scripts/features/reinvoke | 80 + src/kmk/tests/scripts/features/rule_glob | 37 + src/kmk/tests/scripts/features/se_explicit | 169 + src/kmk/tests/scripts/features/se_implicit | 260 + src/kmk/tests/scripts/features/se_statpat | 109 + src/kmk/tests/scripts/features/shell_assignment | 65 + src/kmk/tests/scripts/features/statipattrules | 111 + src/kmk/tests/scripts/features/targetvars | 273 + src/kmk/tests/scripts/features/utf8 | 11 + src/kmk/tests/scripts/features/varnesting | 35 + src/kmk/tests/scripts/features/vpath | 82 + src/kmk/tests/scripts/features/vpath2 | 45 + src/kmk/tests/scripts/features/vpath3 | 41 + src/kmk/tests/scripts/features/vpathgpath | 66 + src/kmk/tests/scripts/features/vpathplus | 132 + src/kmk/tests/scripts/functions/abspath | 81 + src/kmk/tests/scripts/functions/addprefix | 44 + src/kmk/tests/scripts/functions/addsuffix | 36 + src/kmk/tests/scripts/functions/andor | 50 + src/kmk/tests/scripts/functions/basename | 44 + src/kmk/tests/scripts/functions/call | 92 + src/kmk/tests/scripts/functions/dir | 44 + src/kmk/tests/scripts/functions/error | 71 + src/kmk/tests/scripts/functions/eval | 169 + src/kmk/tests/scripts/functions/evalcall | 119 + src/kmk/tests/scripts/functions/expr | 74 + src/kmk/tests/scripts/functions/file | 161 + src/kmk/tests/scripts/functions/filter-out | 42 + src/kmk/tests/scripts/functions/findstring | 47 + src/kmk/tests/scripts/functions/flavor | 44 + src/kmk/tests/scripts/functions/for | 69 + src/kmk/tests/scripts/functions/foreach | 97 + src/kmk/tests/scripts/functions/guile | 99 + src/kmk/tests/scripts/functions/if | 33 + src/kmk/tests/scripts/functions/if-expr | 84 + src/kmk/tests/scripts/functions/insert | 106 + src/kmk/tests/scripts/functions/intersects | 94 + src/kmk/tests/scripts/functions/join | 44 + src/kmk/tests/scripts/functions/lastpos | 118 + src/kmk/tests/scripts/functions/length | 71 + src/kmk/tests/scripts/functions/length-var | 75 + src/kmk/tests/scripts/functions/notdir | 44 + src/kmk/tests/scripts/functions/origin | 54 + src/kmk/tests/scripts/functions/pos | 118 + src/kmk/tests/scripts/functions/printf | 80 + src/kmk/tests/scripts/functions/realpath | 82 + src/kmk/tests/scripts/functions/root | 172 + src/kmk/tests/scripts/functions/select | 96 + src/kmk/tests/scripts/functions/shell | 60 + src/kmk/tests/scripts/functions/sort | 51 + src/kmk/tests/scripts/functions/strip | 57 + src/kmk/tests/scripts/functions/substitution | 38 + src/kmk/tests/scripts/functions/substr | 125 + src/kmk/tests/scripts/functions/suffix | 57 + src/kmk/tests/scripts/functions/translate | 76 + src/kmk/tests/scripts/functions/value | 30 + src/kmk/tests/scripts/functions/warning | 83 + src/kmk/tests/scripts/functions/while | 73 + src/kmk/tests/scripts/functions/wildcard | 103 + src/kmk/tests/scripts/functions/word | 167 + src/kmk/tests/scripts/misc/bs-nl | 227 + src/kmk/tests/scripts/misc/close_stdout | 9 + src/kmk/tests/scripts/misc/fopen-fail | 18 + src/kmk/tests/scripts/misc/general1 | 51 + src/kmk/tests/scripts/misc/general2 | 50 + src/kmk/tests/scripts/misc/general3 | 315 + src/kmk/tests/scripts/misc/general4 | 85 + src/kmk/tests/scripts/misc/utf8 | 14 + src/kmk/tests/scripts/options/dash-B | 87 + src/kmk/tests/scripts/options/dash-C | 71 + src/kmk/tests/scripts/options/dash-I | 59 + src/kmk/tests/scripts/options/dash-W | 91 + src/kmk/tests/scripts/options/dash-e | 24 + src/kmk/tests/scripts/options/dash-f | 85 + src/kmk/tests/scripts/options/dash-k | 114 + src/kmk/tests/scripts/options/dash-l | 56 + src/kmk/tests/scripts/options/dash-n | 100 + src/kmk/tests/scripts/options/dash-q | 86 + src/kmk/tests/scripts/options/dash-t | 58 + src/kmk/tests/scripts/options/eval | 29 + src/kmk/tests/scripts/options/general | 35 + src/kmk/tests/scripts/options/print-directory | 33 + src/kmk/tests/scripts/options/symlinks | 68 + .../tests/scripts/options/warn-undefined-variables | 25 + src/kmk/tests/scripts/targets/DEFAULT | 53 + src/kmk/tests/scripts/targets/DELETE_ON_ERROR | 22 + src/kmk/tests/scripts/targets/FORCE | 40 + src/kmk/tests/scripts/targets/INTERMEDIATE | 112 + src/kmk/tests/scripts/targets/ONESHELL | 88 + src/kmk/tests/scripts/targets/PHONY | 54 + src/kmk/tests/scripts/targets/POSIX | 56 + src/kmk/tests/scripts/targets/SECONDARY | 190 + src/kmk/tests/scripts/targets/SILENT | 42 + src/kmk/tests/scripts/targets/clean | 50 + src/kmk/tests/scripts/test_template | 29 + src/kmk/tests/scripts/variables/CURDIR | 20 + src/kmk/tests/scripts/variables/DEFAULT_GOAL | 87 + src/kmk/tests/scripts/variables/GNUMAKEFLAGS | 42 + src/kmk/tests/scripts/variables/INCLUDE_DIRS | 46 + src/kmk/tests/scripts/variables/LIBPATTERNS | 38 + src/kmk/tests/scripts/variables/MAKE | 24 + src/kmk/tests/scripts/variables/MAKECMDGOALS | 52 + src/kmk/tests/scripts/variables/MAKEFILES | 53 + src/kmk/tests/scripts/variables/MAKEFILE_LIST | 30 + src/kmk/tests/scripts/variables/MAKEFLAGS | 45 + src/kmk/tests/scripts/variables/MAKELEVEL | 45 + src/kmk/tests/scripts/variables/MAKE_RESTARTS | 61 + src/kmk/tests/scripts/variables/MFILE_LIST | 30 + src/kmk/tests/scripts/variables/SHELL | 103 + src/kmk/tests/scripts/variables/automatic | 122 + src/kmk/tests/scripts/variables/define | 282 + src/kmk/tests/scripts/variables/flavors | 96 + src/kmk/tests/scripts/variables/must_make | 81 + src/kmk/tests/scripts/variables/negative | 46 + src/kmk/tests/scripts/variables/private | 122 + src/kmk/tests/scripts/variables/special | 150 + src/kmk/tests/scripts/variables/undefine | 73 + src/kmk/tests/scripts/vms/library | 73 + src/kmk/tests/test_driver.pl | 1498 ++++ src/kmk/variable.c | 3475 +++++++++ src/kmk/variable.h | 551 ++ src/kmk/version.c | 33 + src/kmk/vms_exit.c | 95 + src/kmk/vms_export_symbol.c | 527 ++ src/kmk/vms_export_symbol_test.com | 37 + src/kmk/vms_progname.c | 463 ++ src/kmk/vmsdir.h | 76 + src/kmk/vmsfunctions.c | 226 + src/kmk/vmsify.c | 1005 +++ src/kmk/vmsjobs.c | 1468 ++++ src/kmk/vpath.c | 647 ++ src/kmk/w32/Makefile.am | 26 + src/kmk/w32/Makefile.kup | 0 src/kmk/w32/compat/Makefile.kup | 0 src/kmk/w32/compat/dirent.c | 212 + src/kmk/w32/compat/posixfcn.c | 516 ++ src/kmk/w32/imagecache.c | 219 + src/kmk/w32/include/dirent.h | 66 + src/kmk/w32/include/dlfcn.h | 29 + src/kmk/w32/include/pathstuff.h | 30 + src/kmk/w32/include/sub_proc.h | 72 + src/kmk/w32/include/w32err.h | 26 + src/kmk/w32/pathstuff.c | 321 + src/kmk/w32/subproc/Makefile.kup | 0 src/kmk/w32/subproc/NMakefile | 60 + src/kmk/w32/subproc/misc.c | 83 + src/kmk/w32/subproc/proc.h | 29 + src/kmk/w32/subproc/sub_proc.c | 1714 ++++ src/kmk/w32/subproc/w32err.c | 85 + src/kmk/w32/tstFileInfo.c | 151 + src/kmk/w32/w32os.c | 220 + src/kmk/w32/winchildren.c | 3729 +++++++++ src/kmk/w32/winchildren.h | 115 + 396 files changed, 160922 insertions(+) create mode 100644 src/kmk/.gitignore create mode 100644 src/kmk/.purify create mode 100644 src/kmk/AUTHORS create mode 100644 src/kmk/COPYING create mode 100644 src/kmk/ChangeLog.1 create mode 100644 src/kmk/ChangeLog.2 create mode 100644 src/kmk/ChangeLog.3 create mode 100644 src/kmk/INSTALL create mode 100644 src/kmk/Makefile.DOS.template create mode 100644 src/kmk/Makefile.am create mode 100644 src/kmk/Makefile.ami create mode 100644 src/kmk/Makefile.kmk create mode 100644 src/kmk/Makefile.os2 create mode 100644 src/kmk/NEWS create mode 100644 src/kmk/NMakefile.template create mode 100644 src/kmk/README.Amiga create mode 100644 src/kmk/README.DOS.template create mode 100644 src/kmk/README.OS2.template create mode 100644 src/kmk/README.VMS create mode 100644 src/kmk/README.W32.template create mode 100644 src/kmk/README.customs create mode 100644 src/kmk/README.git create mode 100644 src/kmk/README.template create mode 100644 src/kmk/SCOPTIONS create mode 100644 src/kmk/SMakefile.template create mode 100644 src/kmk/TODO.private create mode 100644 src/kmk/acinclude.m4 create mode 100644 src/kmk/alloca.c create mode 100644 src/kmk/alloccache.c create mode 100644 src/kmk/amiga.c create mode 100644 src/kmk/amiga.h create mode 100644 src/kmk/ar.c create mode 100644 src/kmk/arscan.c create mode 100644 src/kmk/build.template create mode 100644 src/kmk/build_w32.bat create mode 100644 src/kmk/commands.c create mode 100644 src/kmk/commands.h create mode 100644 src/kmk/config.ami.template create mode 100644 src/kmk/config.h-vms.template create mode 100644 src/kmk/config.h.W32.template create mode 100644 src/kmk/config.h.darwin create mode 100644 src/kmk/config.h.freebsd create mode 100644 src/kmk/config.h.haiku create mode 100644 src/kmk/config.h.linux create mode 100755 src/kmk/config.h.netbsd create mode 100644 src/kmk/config.h.os2 create mode 100644 src/kmk/config.h.solaris create mode 100644 src/kmk/config.h.win create mode 100644 src/kmk/config/.gitignore create mode 100644 src/kmk/config/ChangeLog.1 create mode 100644 src/kmk/config/Makefile.am create mode 100644 src/kmk/config/dospaths.m4 create mode 100644 src/kmk/configh.dos.template create mode 100644 src/kmk/configure.ac create mode 100644 src/kmk/configure.bat create mode 100644 src/kmk/debug.h create mode 100644 src/kmk/default.c create mode 100644 src/kmk/dep.h create mode 100644 src/kmk/dir-nt-bird.c create mode 100644 src/kmk/dir.c create mode 100644 src/kmk/doc/.gitignore create mode 100644 src/kmk/doc/Makefile.am create mode 100644 src/kmk/dosbuild.bat create mode 100644 src/kmk/electric.c create mode 100644 src/kmk/electric.h create mode 100644 src/kmk/example-spaces.kmk create mode 100644 src/kmk/expand.c create mode 100644 src/kmk/expreval.c create mode 100644 src/kmk/file.c create mode 100644 src/kmk/filedef.h create mode 100644 src/kmk/function.c create mode 100644 src/kmk/getloadavg.c create mode 100644 src/kmk/getopt.c create mode 100644 src/kmk/getopt.h create mode 100644 src/kmk/getopt1.c create mode 100644 src/kmk/gettext.h create mode 100644 src/kmk/glob/COPYING.LIB create mode 100644 src/kmk/glob/ChangeLog create mode 100644 src/kmk/glob/Makefile.am create mode 100644 src/kmk/glob/Makefile.ami create mode 100644 src/kmk/glob/SCOPTIONS create mode 100644 src/kmk/glob/SMakefile create mode 100644 src/kmk/glob/configure.bat create mode 100644 src/kmk/glob/fnmatch.c create mode 100644 src/kmk/glob/fnmatch.h create mode 100644 src/kmk/glob/glob.c create mode 100644 src/kmk/glob/glob.h create mode 100644 src/kmk/gmk-default.scm create mode 100644 src/kmk/gnumake.h create mode 100644 src/kmk/guile.c create mode 100644 src/kmk/hash.c create mode 100644 src/kmk/hash.h create mode 100644 src/kmk/implicit.c create mode 100644 src/kmk/incdep.c create mode 100644 src/kmk/inlined_memchr.h create mode 100644 src/kmk/job.c create mode 100644 src/kmk/job.h create mode 100644 src/kmk/kbuild-object.c create mode 100644 src/kmk/kbuild.c create mode 100644 src/kmk/kbuild.h create mode 100644 src/kmk/kbuildprf.c create mode 100644 src/kmk/kdepdb.c create mode 100644 src/kmk/kmk_cc_exec.c create mode 100644 src/kmk/kmk_cc_exec.h create mode 100644 src/kmk/kmkbuiltin.c create mode 100644 src/kmk/kmkbuiltin.h create mode 100644 src/kmk/kmkbuiltin/Makefile.kup create mode 100644 src/kmk/kmkbuiltin/append.c create mode 100644 src/kmk/kmkbuiltin/cat.c create mode 100644 src/kmk/kmkbuiltin/chmod.c create mode 100644 src/kmk/kmkbuiltin/cmp.c create mode 100644 src/kmk/kmkbuiltin/cmp_extern.h create mode 100644 src/kmk/kmkbuiltin/cmp_util.c create mode 100644 src/kmk/kmkbuiltin/common-env-and-cwd-opt.c create mode 100644 src/kmk/kmkbuiltin/cp.c create mode 100644 src/kmk/kmkbuiltin/cp_extern.h create mode 100644 src/kmk/kmkbuiltin/cp_utils.c create mode 100644 src/kmk/kmkbuiltin/darwin.c create mode 100644 src/kmk/kmkbuiltin/echo.c create mode 100644 src/kmk/kmkbuiltin/err.c create mode 100644 src/kmk/kmkbuiltin/err.h create mode 100644 src/kmk/kmkbuiltin/expr.c create mode 100644 src/kmk/kmkbuiltin/fts.c create mode 100644 src/kmk/kmkbuiltin/ftsfake.h create mode 100644 src/kmk/kmkbuiltin/getopt1_r.c create mode 100644 src/kmk/kmkbuiltin/getopt_r.c create mode 100644 src/kmk/kmkbuiltin/getopt_r.h create mode 100644 src/kmk/kmkbuiltin/haikufakes.c create mode 100644 src/kmk/kmkbuiltin/haikufakes.h create mode 100644 src/kmk/kmkbuiltin/install.c create mode 100644 src/kmk/kmkbuiltin/kDepIDB.c create mode 100644 src/kmk/kmkbuiltin/kDepObj.c create mode 100644 src/kmk/kmkbuiltin/kSubmit.c create mode 100644 src/kmk/kmkbuiltin/kbuild_protection.c create mode 100644 src/kmk/kmkbuiltin/kbuild_protection.h create mode 100644 src/kmk/kmkbuiltin/kill.c create mode 100644 src/kmk/kmkbuiltin/ln.c create mode 100644 src/kmk/kmkbuiltin/md5sum.c create mode 100644 src/kmk/kmkbuiltin/mkdir.c create mode 100644 src/kmk/kmkbuiltin/mscfakes.c create mode 100644 src/kmk/kmkbuiltin/mscfakes.h create mode 100644 src/kmk/kmkbuiltin/mv.c create mode 100644 src/kmk/kmkbuiltin/openbsd.c create mode 100644 src/kmk/kmkbuiltin/osdep.c create mode 100644 src/kmk/kmkbuiltin/printf.c create mode 100644 src/kmk/kmkbuiltin/redirect.c create mode 100644 src/kmk/kmkbuiltin/rm.c create mode 100644 src/kmk/kmkbuiltin/rmdir.c create mode 100644 src/kmk/kmkbuiltin/setmode.c create mode 100644 src/kmk/kmkbuiltin/sleep.c create mode 100644 src/kmk/kmkbuiltin/solfakes.c create mode 100644 src/kmk/kmkbuiltin/solfakes.h create mode 100644 src/kmk/kmkbuiltin/strlcpy.c create mode 100644 src/kmk/kmkbuiltin/strmode.c create mode 100644 src/kmk/kmkbuiltin/test.c create mode 100644 src/kmk/kmkbuiltin/touch.c create mode 100644 src/kmk/load.c create mode 100644 src/kmk/loadapi.c create mode 100644 src/kmk/main.c create mode 100644 src/kmk/maintMakefile create mode 100644 src/kmk/make.1 create mode 100644 src/kmk/make.lnk create mode 100644 src/kmk/make_msvc_net2003.sln create mode 100644 src/kmk/make_msvc_net2003.vcproj create mode 100644 src/kmk/makefile.com create mode 100644 src/kmk/makefile.vms create mode 100644 src/kmk/makeint.h create mode 100644 src/kmk/misc.c create mode 100644 src/kmk/os.h create mode 100644 src/kmk/output.c create mode 100644 src/kmk/output.h create mode 100644 src/kmk/po/.gitignore create mode 100644 src/kmk/po/LINGUAS create mode 100644 src/kmk/po/Makevars create mode 100644 src/kmk/po/POTFILES.in create mode 100644 src/kmk/posixos.c create mode 100644 src/kmk/prepare_vms.com create mode 100644 src/kmk/prepare_w32.bat create mode 100644 src/kmk/read.c create mode 100644 src/kmk/remake.c create mode 100644 src/kmk/remote-cstms.c create mode 100644 src/kmk/remote-stub.c create mode 100644 src/kmk/rule.c create mode 100644 src/kmk/rule.h create mode 100644 src/kmk/signame.c create mode 100644 src/kmk/strcache.c create mode 100644 src/kmk/strcache2.c create mode 100644 src/kmk/strcache2.h create mode 100644 src/kmk/subproc.bat create mode 100644 src/kmk/testcase-2ndtargetexp.kmk create mode 100644 src/kmk/testcase-assignments.kmk create mode 100644 src/kmk/testcase-if1of.kmk create mode 100644 src/kmk/testcase-ifeq-escape.kmk create mode 100644 src/kmk/testcase-includedep-esc-sub.kmk create mode 100644 src/kmk/testcase-includedep-esc.kmk create mode 100644 src/kmk/testcase-includedep-sub.kmk create mode 100644 src/kmk/testcase-includedep.kmk create mode 100644 src/kmk/testcase-kBuild-define.kmk create mode 100644 src/kmk/testcase-lazy-deps-vars.kmk create mode 100644 src/kmk/testcase-libpath.kmk create mode 100644 src/kmk/testcase-local.kmk create mode 100644 src/kmk/testcase-math.kmk create mode 100644 src/kmk/testcase-root.kmk create mode 100644 src/kmk/testcase-stack.kmk create mode 100644 src/kmk/testcase-which.kmk create mode 100644 src/kmk/testcase-xargs.kmk create mode 100644 src/kmk/testcase/testcase-export.kmk create mode 100644 src/kmk/tests/.gitignore create mode 100644 src/kmk/tests/COPYING create mode 100644 src/kmk/tests/ChangeLog.1 create mode 100644 src/kmk/tests/NEWS create mode 100644 src/kmk/tests/README create mode 100644 src/kmk/tests/config-flags.pm.in create mode 100644 src/kmk/tests/config_flags_pm.com create mode 100644 src/kmk/tests/guile.supp create mode 100755 src/kmk/tests/mkshadow create mode 100755 src/kmk/tests/run_make_tests create mode 100644 src/kmk/tests/run_make_tests.com create mode 100755 src/kmk/tests/run_make_tests.pl create mode 100644 src/kmk/tests/scripts/features/archives create mode 100644 src/kmk/tests/scripts/features/comments create mode 100644 src/kmk/tests/scripts/features/conditionals create mode 100644 src/kmk/tests/scripts/features/default_names create mode 100644 src/kmk/tests/scripts/features/double_colon create mode 100644 src/kmk/tests/scripts/features/echoing create mode 100644 src/kmk/tests/scripts/features/errors create mode 100644 src/kmk/tests/scripts/features/escape create mode 100644 src/kmk/tests/scripts/features/export create mode 100644 src/kmk/tests/scripts/features/ifcond create mode 100644 src/kmk/tests/scripts/features/include create mode 100644 src/kmk/tests/scripts/features/jobserver create mode 100644 src/kmk/tests/scripts/features/load create mode 100644 src/kmk/tests/scripts/features/loadapi create mode 100644 src/kmk/tests/scripts/features/mult_rules create mode 100644 src/kmk/tests/scripts/features/mult_targets create mode 100644 src/kmk/tests/scripts/features/order_only create mode 100644 src/kmk/tests/scripts/features/output-sync create mode 100644 src/kmk/tests/scripts/features/override create mode 100644 src/kmk/tests/scripts/features/parallelism create mode 100644 src/kmk/tests/scripts/features/patspecific_vars create mode 100644 src/kmk/tests/scripts/features/patternrules create mode 100644 src/kmk/tests/scripts/features/quoting create mode 100644 src/kmk/tests/scripts/features/recursion create mode 100644 src/kmk/tests/scripts/features/reinvoke create mode 100644 src/kmk/tests/scripts/features/rule_glob create mode 100644 src/kmk/tests/scripts/features/se_explicit create mode 100644 src/kmk/tests/scripts/features/se_implicit create mode 100644 src/kmk/tests/scripts/features/se_statpat create mode 100644 src/kmk/tests/scripts/features/shell_assignment create mode 100644 src/kmk/tests/scripts/features/statipattrules create mode 100644 src/kmk/tests/scripts/features/targetvars create mode 100644 src/kmk/tests/scripts/features/utf8 create mode 100644 src/kmk/tests/scripts/features/varnesting create mode 100644 src/kmk/tests/scripts/features/vpath create mode 100644 src/kmk/tests/scripts/features/vpath2 create mode 100644 src/kmk/tests/scripts/features/vpath3 create mode 100644 src/kmk/tests/scripts/features/vpathgpath create mode 100644 src/kmk/tests/scripts/features/vpathplus create mode 100644 src/kmk/tests/scripts/functions/abspath create mode 100644 src/kmk/tests/scripts/functions/addprefix create mode 100644 src/kmk/tests/scripts/functions/addsuffix create mode 100644 src/kmk/tests/scripts/functions/andor create mode 100644 src/kmk/tests/scripts/functions/basename create mode 100644 src/kmk/tests/scripts/functions/call create mode 100644 src/kmk/tests/scripts/functions/dir create mode 100644 src/kmk/tests/scripts/functions/error create mode 100644 src/kmk/tests/scripts/functions/eval create mode 100644 src/kmk/tests/scripts/functions/evalcall create mode 100644 src/kmk/tests/scripts/functions/expr create mode 100644 src/kmk/tests/scripts/functions/file create mode 100644 src/kmk/tests/scripts/functions/filter-out create mode 100644 src/kmk/tests/scripts/functions/findstring create mode 100644 src/kmk/tests/scripts/functions/flavor create mode 100644 src/kmk/tests/scripts/functions/for create mode 100644 src/kmk/tests/scripts/functions/foreach create mode 100644 src/kmk/tests/scripts/functions/guile create mode 100644 src/kmk/tests/scripts/functions/if create mode 100644 src/kmk/tests/scripts/functions/if-expr create mode 100644 src/kmk/tests/scripts/functions/insert create mode 100644 src/kmk/tests/scripts/functions/intersects create mode 100644 src/kmk/tests/scripts/functions/join create mode 100644 src/kmk/tests/scripts/functions/lastpos create mode 100644 src/kmk/tests/scripts/functions/length create mode 100644 src/kmk/tests/scripts/functions/length-var create mode 100644 src/kmk/tests/scripts/functions/notdir create mode 100644 src/kmk/tests/scripts/functions/origin create mode 100644 src/kmk/tests/scripts/functions/pos create mode 100644 src/kmk/tests/scripts/functions/printf create mode 100644 src/kmk/tests/scripts/functions/realpath create mode 100644 src/kmk/tests/scripts/functions/root create mode 100644 src/kmk/tests/scripts/functions/select create mode 100644 src/kmk/tests/scripts/functions/shell create mode 100644 src/kmk/tests/scripts/functions/sort create mode 100644 src/kmk/tests/scripts/functions/strip create mode 100644 src/kmk/tests/scripts/functions/substitution create mode 100644 src/kmk/tests/scripts/functions/substr create mode 100644 src/kmk/tests/scripts/functions/suffix create mode 100644 src/kmk/tests/scripts/functions/translate create mode 100644 src/kmk/tests/scripts/functions/value create mode 100644 src/kmk/tests/scripts/functions/warning create mode 100644 src/kmk/tests/scripts/functions/while create mode 100644 src/kmk/tests/scripts/functions/wildcard create mode 100644 src/kmk/tests/scripts/functions/word create mode 100644 src/kmk/tests/scripts/misc/bs-nl create mode 100644 src/kmk/tests/scripts/misc/close_stdout create mode 100644 src/kmk/tests/scripts/misc/fopen-fail create mode 100644 src/kmk/tests/scripts/misc/general1 create mode 100644 src/kmk/tests/scripts/misc/general2 create mode 100644 src/kmk/tests/scripts/misc/general3 create mode 100644 src/kmk/tests/scripts/misc/general4 create mode 100644 src/kmk/tests/scripts/misc/utf8 create mode 100644 src/kmk/tests/scripts/options/dash-B create mode 100644 src/kmk/tests/scripts/options/dash-C create mode 100644 src/kmk/tests/scripts/options/dash-I create mode 100644 src/kmk/tests/scripts/options/dash-W create mode 100644 src/kmk/tests/scripts/options/dash-e create mode 100644 src/kmk/tests/scripts/options/dash-f create mode 100644 src/kmk/tests/scripts/options/dash-k create mode 100644 src/kmk/tests/scripts/options/dash-l create mode 100644 src/kmk/tests/scripts/options/dash-n create mode 100644 src/kmk/tests/scripts/options/dash-q create mode 100644 src/kmk/tests/scripts/options/dash-t create mode 100644 src/kmk/tests/scripts/options/eval create mode 100644 src/kmk/tests/scripts/options/general create mode 100644 src/kmk/tests/scripts/options/print-directory create mode 100644 src/kmk/tests/scripts/options/symlinks create mode 100644 src/kmk/tests/scripts/options/warn-undefined-variables create mode 100644 src/kmk/tests/scripts/targets/DEFAULT create mode 100644 src/kmk/tests/scripts/targets/DELETE_ON_ERROR create mode 100644 src/kmk/tests/scripts/targets/FORCE create mode 100644 src/kmk/tests/scripts/targets/INTERMEDIATE create mode 100644 src/kmk/tests/scripts/targets/ONESHELL create mode 100644 src/kmk/tests/scripts/targets/PHONY create mode 100644 src/kmk/tests/scripts/targets/POSIX create mode 100644 src/kmk/tests/scripts/targets/SECONDARY create mode 100644 src/kmk/tests/scripts/targets/SILENT create mode 100644 src/kmk/tests/scripts/targets/clean create mode 100644 src/kmk/tests/scripts/test_template create mode 100644 src/kmk/tests/scripts/variables/CURDIR create mode 100644 src/kmk/tests/scripts/variables/DEFAULT_GOAL create mode 100644 src/kmk/tests/scripts/variables/GNUMAKEFLAGS create mode 100644 src/kmk/tests/scripts/variables/INCLUDE_DIRS create mode 100644 src/kmk/tests/scripts/variables/LIBPATTERNS create mode 100644 src/kmk/tests/scripts/variables/MAKE create mode 100644 src/kmk/tests/scripts/variables/MAKECMDGOALS create mode 100644 src/kmk/tests/scripts/variables/MAKEFILES create mode 100644 src/kmk/tests/scripts/variables/MAKEFILE_LIST create mode 100644 src/kmk/tests/scripts/variables/MAKEFLAGS create mode 100644 src/kmk/tests/scripts/variables/MAKELEVEL create mode 100644 src/kmk/tests/scripts/variables/MAKE_RESTARTS create mode 100644 src/kmk/tests/scripts/variables/MFILE_LIST create mode 100644 src/kmk/tests/scripts/variables/SHELL create mode 100644 src/kmk/tests/scripts/variables/automatic create mode 100644 src/kmk/tests/scripts/variables/define create mode 100644 src/kmk/tests/scripts/variables/flavors create mode 100644 src/kmk/tests/scripts/variables/must_make create mode 100644 src/kmk/tests/scripts/variables/negative create mode 100644 src/kmk/tests/scripts/variables/private create mode 100644 src/kmk/tests/scripts/variables/special create mode 100644 src/kmk/tests/scripts/variables/undefine create mode 100644 src/kmk/tests/scripts/vms/library create mode 100644 src/kmk/tests/test_driver.pl create mode 100644 src/kmk/variable.c create mode 100644 src/kmk/variable.h create mode 100644 src/kmk/version.c create mode 100644 src/kmk/vms_exit.c create mode 100644 src/kmk/vms_export_symbol.c create mode 100644 src/kmk/vms_export_symbol_test.com create mode 100644 src/kmk/vms_progname.c create mode 100644 src/kmk/vmsdir.h create mode 100644 src/kmk/vmsfunctions.c create mode 100644 src/kmk/vmsify.c create mode 100644 src/kmk/vmsjobs.c create mode 100644 src/kmk/vpath.c create mode 100644 src/kmk/w32/Makefile.am create mode 100644 src/kmk/w32/Makefile.kup create mode 100644 src/kmk/w32/compat/Makefile.kup create mode 100644 src/kmk/w32/compat/dirent.c create mode 100644 src/kmk/w32/compat/posixfcn.c create mode 100644 src/kmk/w32/imagecache.c create mode 100644 src/kmk/w32/include/dirent.h create mode 100644 src/kmk/w32/include/dlfcn.h create mode 100644 src/kmk/w32/include/pathstuff.h create mode 100644 src/kmk/w32/include/sub_proc.h create mode 100644 src/kmk/w32/include/w32err.h create mode 100644 src/kmk/w32/pathstuff.c create mode 100644 src/kmk/w32/subproc/Makefile.kup create mode 100644 src/kmk/w32/subproc/NMakefile create mode 100644 src/kmk/w32/subproc/misc.c create mode 100644 src/kmk/w32/subproc/proc.h create mode 100644 src/kmk/w32/subproc/sub_proc.c create mode 100644 src/kmk/w32/subproc/w32err.c create mode 100644 src/kmk/w32/tstFileInfo.c create mode 100644 src/kmk/w32/w32os.c create mode 100644 src/kmk/w32/winchildren.c create mode 100644 src/kmk/w32/winchildren.h (limited to 'src/kmk') diff --git a/src/kmk/.gitignore b/src/kmk/.gitignore new file mode 100644 index 0000000..0764966 --- /dev/null +++ b/src/kmk/.gitignore @@ -0,0 +1,62 @@ +# Development artifacts +ID +TAGS +.*gdbinit +.gdb_history +*~ +#* +.#* + +# Configure artifacts +ABOUT-NLS +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +config.cache +config.h +config.h.in +config.log +config.status +configure +stamp-h1 + +# Build artifacts +.deps +gmk-default.h +loadavg +make +*.o +*.exe +*.dll.a +*.obj +*.lib +*.pdb +*.sbr + +# Windows build artifacts +WinDebug/ +WinRel/ +GccDebug/ +GccRel/ + +# Distribution artifacts +.dep_segment +.check-git-HEAD +ChangeLog +Makefile.DOS +NMakefile +README +README.DOS +README.OS2 +README.W32 +SMakefile +build.sh +build.sh.in +config.ami +config.h-vms +config.h.W32 +configh.dos +make-[0-9]*/ +make-[0-9]*.tar.* +checkcfg.*.log diff --git a/src/kmk/.purify b/src/kmk/.purify new file mode 100644 index 0000000..dc1b1d9 --- /dev/null +++ b/src/kmk/.purify @@ -0,0 +1,12 @@ +# Solaris (2.5.1) has a couple if issues. +# +suppress plk malloc; setvbuf "libc*"; main "main.c" +suppress umr kstat_read; kstat_chain_update; kstat_open; getloadavg +suppress umr kstat_chain_update; kstat_open; getloadavg + +# The command line options stuff leaks a little bit. No big deal. +# +suppress mlk malloc; xmalloc "misc.c"; decode_env_switches "main.c" +suppress plk malloc; xmalloc "misc.c"; decode_env_switches "main.c" +suppress mlk malloc; xmalloc "misc.c"; concat "misc.c"; decode_env_switches "main.c" +suppress plk malloc; xmalloc "misc.c"; concat "misc.c"; decode_env_switches "main.c" diff --git a/src/kmk/AUTHORS b/src/kmk/AUTHORS new file mode 100644 index 0000000..9b6212f --- /dev/null +++ b/src/kmk/AUTHORS @@ -0,0 +1,88 @@ +----------------------------------- + +GNU make development up to version 3.75 by: + Roland McGrath + + +Development starting with GNU make 3.76 by: + Paul D. Smith + + Additional development starting with GNU make 3.81 by: + Boris Kolpackov + + +GNU Make User's Manual + Written by: + Richard M. Stallman + + Edited by: + Roland McGrath + Bob Chassell + Melissa Weisshaus + Paul D. Smith + +----------------------------------- +GNU make porting efforts: + + Port to VMS by: + Klaus Kaempf + Hartmut Becker + Archive support/Bug fixes by: + John W. Eaton + Martin Zinser + + Port to Amiga by: + Aaron Digulla + + Port to MS-DOS (DJGPP), OS/2, and MS-Windows (native/MinGW) by: + DJ Delorie + Rob Tulloh + Eli Zaretskii + Jonathan Grant + Andreas Beuning + Earnie Boyd + Troy Runkel + +----------------------------------- +Other contributors: + + Janet Carson + Howard Chu + Ludovic Courtès + Paul Eggert + Ramon Garcia Fernandez + Klaus Heinz + Michael Joosten + Jim Kelton + David Lubbren + Tim Magill + Markus Mauhart + Greg McGary + Thien-Thi Nguyen + Thomas Riedl + Han-Wen Nienhuys + Andreas Schwab + Carl Staelin (Princeton University) + Ian Stewartson (Data Logic Limited) + David A. Wheeler + David Boyce + Frank Heckenbach + +With suggestions/comments/bug reports from a cast of ... well ... +hundreds, anyway :) + +------------------------------------------------------------------------------- +Copyright (C) 1997-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . diff --git a/src/kmk/COPYING b/src/kmk/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/src/kmk/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/src/kmk/ChangeLog.1 b/src/kmk/ChangeLog.1 new file mode 100644 index 0000000..c37b139 --- /dev/null +++ b/src/kmk/ChangeLog.1 @@ -0,0 +1,4997 @@ +Tue Oct 29 20:57:36 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.62. + + * remake.c (update_file_1): Check for deps still running before + giving up if any dep has failed. + +Sat Oct 26 16:20:00 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * make.h [uts]: #undef S_ISREG and S_ISDIR if defined. + +Fri Oct 25 19:50:39 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.60.17. + +Thu Oct 24 16:58:36 1991 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) + + * job.c (start_job): Don't check for empty cmds before tweaking the + command_ptr. Just let construct_command_argv do it. + +Tue Oct 22 20:21:03 1991 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) + + * remake.c, arscan.c [POSIX]: instead of . + + * make.h [POSIX]: Declare vfork as pid_t. + +Mon Oct 21 15:37:30 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.60.16. + + * job.c (construct_command_argv, construct_command_argv_internal): + Take new 2nd arg RESTP. If non-NULL, stop parsing at newline, and + store addr of the NL in *RESTP. + (start_job): Don't chop expanded cmd lines up; use above code to do it. + * function.c (expand_function: `shell'): Pass RESTP==NULL. + +Sat Oct 19 15:36:34 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.60.15. + +Fri Oct 18 15:26:55 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * job.c (start_job): If on the same cmds->command_lines elt, look + at cmds->lines_recurse[CHILD->command_line - 1] instead of + [CHILD->command_line]. + + * dir.c [sgi]: , not ndir or anything else. + +Thu Oct 17 16:28:55 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * file.c (print_file_data_base): Remove unused var. + + * make.h [NeXT]: No #define ANSI_STRING. + +Tue Oct 15 20:08:41 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.60.14. + +Fri Oct 11 16:23:52 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * make.h: Use PATH_MAX for getwd defn. + + * make.h: Move getcwd/getwd outside of #ifndef POSIX, and make it + #if USG||POSIX. + +Thu Oct 10 11:53:31 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.60.13. + + * read.c (read_all_makefiles): When processing MAKEFILES, save the + malloc'd ptr to be freed, instead of freeing part-way thru it. + + * remake.c (update_file_1): Don't tweak FILE->also_make. + (update_file): Do it here. After calling update_file_1, set the + command_state, update_status, and updated members of each also_make + elt to FILE's values. + +Tue Oct 8 14:56:04 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * Version 3.60.12. + + * remake.c (notice_finished_file): Set command_state of FILE and + its also_make chain to cs_finished here. + * commands.c (execute_file_commands), job.c (child_handler), + remake.c (remake_file): Don't set it before calling + notice_finished_file. + + * file.h (struct file): Changed `also_make' to struct dep *. + * job.c (delete_child_targets), file.c (print_file_data_base), + remake.c (notice_finished_file), implicit.c (pattern_search): + Use dep chain instead of array of file names. + +Mon Oct 7 17:04:33 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.60.11. + + * arscan.c: Declare open. + * misc.c: Declare {get,set}{re,}[ug]id. + * variable.c (target_environment): Declare getenv. + +Sat Oct 5 15:13:03 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * make.h [NeXT]: instead of . + +Fri Oct 4 16:05:41 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * default.c (default_suffixes, defualt_suffix_rules): Add .texi + just like .texinfo. + + * Version 3.60.10. + + * job.c: Move vfork decl into make.h. + +Fri Sep 27 18:45:30 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * compatMakefile (glob/libglob.a): Pass CC value to submake. + +Thu Sep 26 00:08:15 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * load.c (load_average): Made not static. + + * load.c [ultrix && vax]: Define LDAV_TYPE and LDAV_CVT for Ultrix 4.2. + +Tue Sep 24 00:17:20 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.60.9. + + * read.c (record_files): Warn about extra cmds even if the target's + name begins with a dot. I think the lusers can handle this. + +Mon Sep 23 22:33:26 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * make.h, arscan.c: Don't declare bcmp, bzero, or bcopy if they're + #define'd. + * make.h: Declare write and open. + + * default.c (default_suffixes, default_suffix_rules, + default_variables): Add .C just like .cc. + * make.texinfo (Catalogue of Rules): Document .C. + + * make.man (-w): Fix gramo. + +Fri Sep 20 17:18:16 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * make.h: No text after #endif. + +Sun Sep 15 16:20:46 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * Version 3.60.8. + + * implicit.c (pattern_search): In the second pass, recurse on rule + deps that don't have a %. Why did I make it not do this? + +Fri Sep 14 18:29:39 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * read.c (record_files): For extra cmds, use the last ones given. + If the target's name doesn't begin with a dot (bletch!!), emit a + two-line warning, one line giving the old cmds' location and the + other the new cmds' location. + + * misc.c (makefile_error, makefile_fatal): New fns. + * make.h: Declare them. + * Use them instead of error/fatal for all msgs including a file + name and line number. + +Thu Sep 13 16:35:54 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * make.h: Declare define_default_variables. + Declare ar_parse_name, instead of ar_name_parse (M-t). + +Mon Sep 10 18:35:40 1991 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) + + * Version 3.60.7. + + * make.texinfo (Variables: Setting): Say whitespace is removed if + "immediately after =", rather than simply "after =". + + * job.c: Don't declare wait #ifdef POSIX. + + * make.h [__GNUC__]: #undef alloca and then #define it. + + * main.c (main): When pruning makefiles which might loop from the + read_makefiles chain, look at all `prev' entries of double-colon rules. + +Fri Sep 7 00:41:53 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * main.c (main): Only remove makefiles with cmds but no deps from + the list of makefiles to be rebuilt if they are :: targets. + : targets with cmds and no deps are not dangerous. + +Wed Sep 5 17:35:51 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * compatMakefile (defines): Add comment that some compilers take + ENUM_BITFIELDS but produce bogus code. + (LOAD_AVG): Fix examples to \ "s. + (LOADLIBES): Add comment that SGI Irix needs -lmld for nlist. + +Tue Sep 4 20:26:26 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.60.6. + +Fri Aug 30 19:34:04 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * remake.c (update_file_1): When checking the command_state of + deps, check through the prev chain. + (update_goal_chain): When a target is finished, start checking its + prev (if it has one) instead. + +Wed Aug 7 17:32:03 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * rule.c (convert_to_pattern): Allow files with deps to define + suffix rules (really this time). + +Mon Aug 5 17:09:21 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * misc.c (user_access, make_access): Do saved-IDs (USG) flavor + #ifdef POSIX. + + * file.c (enter_file): Strip ./s here. + * read.c (parse_file_seq): Not here. + +Tue Jul 23 23:34:30 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * compatMakefile: Added comment that -lPW alloca is broken on HPUX. + +Thu Jul 18 03:10:41 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.60.5. + + * read.c (read_makefile): Ignore lines containing chars that are + all isspace, not just all isblank. + + * make.texinfo (Copying): @include gpl.texinfo, rather than copying + the text. + * gpl.texinfo: New file (symlink to /gd/gnu/doc/gpl.texinfo). + * GNUmakefile: Put gpl.texinfo in distribution. + +Tue Jul 16 12:50:35 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * make.h: #define _GNU_SOURCE before including headers. + Include and define isblank if doesn't. + * commands.c: Don't include here. + * *.c: Use isblank instead of explicit ' ' || '\t'. + +Mon Jul 15 17:43:38 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * function.c (expand_function: `filter'/`filter-out'): Fixed to not + loop infinitely. + +Fri Jul 12 12:18:12 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * function.c (expand_function: `filter'/`filter-out'): Rewritten to + handle filter-out of multiple patterns properly. Also no longer + mallocs and reallocs for temp array; uses alloca and a linked-list + instead. + +Wed Jul 10 22:34:54 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.60.4. + + * make.texinfo: Moved some @groups that were outside @examples to + be inside them. + + * load.c [apollo] (load_average): Define using special syscall for + Apollo DOMAIN/OS SR10.n. + +Thu Jul 4 12:32:53 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * make.texinfo (Missing): Added Unix excessive implicit rule + search; mention that POSIX.2 doesn't require any of the missing + features. + (Top): Updated printed manual price to $15. + +Wed Jul 3 18:17:50 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * file.c (rename_file): Carry over last_mtime when merging files. + * remake.c (f_mtime): Tail-recurse after renaming VPATH file, to + check for saved date in existing renamed-to file. + + * remote-cstms.c (start_remote_job): Use PATH_VAR. + + * commands.c [POSIX || __GNU_LIBRARY__]: Don't declare getpid. + + * compatMakefile (glob-{clean,realclean}): Run clean/realclean in glob. + (clean, realclean): Require those. + + * make.h: Always declare environ. + Don't declare old glob functions. + + * GNUmakefile: Make no-lib deps for load.c and remote.c. + +Tue Jul 2 18:35:20 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.60.3. + +Mon Jul 1 16:58:30 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * read.c (multi_glob): Don't pass GLOB_QUOTE flag to glob. + + * make.h [POSIX]: Include , and don't declare things that + should be there. + + * main.c (main) [USG && sgi]: malloc a buffer for broken sgi stdio. + +Sat Jun 29 11:22:21 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * function.c (expand_function: `shell'): Use alloca for the error + msg buffer, instead of assuming an arbitrary max size. + +Fri Jun 28 18:15:08 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * job.c [POSIX] (search_path): Do real 1003.1 goop to get NGROUPS_MAX. + +Wed Jun 26 11:04:44 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * default.c (define_default_variables): New fn. + (install_default_implicit_rules): Code for above fn moved there. + * main.c (main): Do define_default_variables before reading the + makefile. + +Tue Jun 25 17:30:46 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * main.c (main): Quote ; in MAKEOVERRIDES. + +Tue Jun 18 13:56:30 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * compatMakefile: Fixed typo in comment. + +Tue Jun 11 00:14:59 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * Version 3.60.2. + +Mon Jun 10 14:46:37 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * make.h: Always include . + [POSIX]: Include and #define MAXPATHLEN to be PATH_MAX. + + * default.c (default_suffix_rules: .texinfo.dvi): Use $(TEXI2DVI). + (default_variables): Define TEXI2DVI. + +Thu Jun 6 16:49:19 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.60.1. + + * make.h (SIGNAL): Cast handler arg to SIGHANDLER type. + +Wed Jun 5 06:00:43 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * read.c (multi_glob): Use POSIX.2 `glob' function. + If a glob pattern matches nothing, leave it as is (a la sh, bash). + Also, if can't find USER for ~USER, leave it as is (a la bash). + +Mon Jun 3 16:36:00 1991 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * compatMakefile: Rewrote comments about -Ds to be easier to use. + + * make.h, arscan.c, remake.c, main.c, dir.c, job.c: Changed tests + of _POSIX_SOURCE to POSIX. + + * job.c: Take getdtablesize out of #ifdef __GNU_LIBRARY__. + Put separately #ifdef USG. + + * COPYING: Replaced with version 2. + * Changed copyright notices to refer to GPL v2. + +Thu May 30 00:31:11 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * make.h: Don't declare sigblock for POSIX. + + * main.c (main, log_working_directory) [USG]: Get getcwd failure + mode from errno, not passed buffer like BSD getwd. + + * misc.c (child_access): New fn to set access for a child process; + like user_access, but you can't change back. + * make.h: Declare it. + * job.c (exec_command): Use it in place of user_access. + +Wed May 29 23:28:48 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * default.c (default_variables) [pyr]: PC = pascal. + +Tue May 28 20:24:56 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * variable.c (print_variable): Put a newline before `endef'. + +Sat May 25 02:39:52 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.60. + +Wed May 22 19:41:37 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.59.5. + +Thu May 16 13:59:24 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * main.c (main): Do USGr3 setvbuf behavior #ifdef APOLLO. + Don't handle SIGCHLD #ifdef USG (Apollo is USG but defines SIGCHLD). + +Fri May 10 14:59:33 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * remake.c [sgi]: Don't include . + +Wed May 8 01:54:08 1991 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * make.h (SIGHANDLER): #define as (void *) #if __STDC__, + else (int (*)()). + (SIGNAL): Use it to cast return value. + * main.c (main): Cast SIG_IGN to SIGHANDLER when comparing. + * job.c (block_signals, unblock_signals): Use SIGNAL instead of signal. + + * main.c: Declare mktemp to return char*, not int. + + * job.c (new_job): Don't increment files_remade. + * remake.c (notice_finished_file): Do it here. + + * read.c (do_define): Don't clobber DEFINITION[-1] on empty defns. + Free storage that is no longer needed. + +Wed Apr 24 20:49:48 1991 Roland McGrath (roland at churchy.gnu.ai.mit.edu) + + * misc.c (message): New fn to print informational msgs with + leading "make: " or "make[N]: ". + * make.h: Declare it. + * remake.c (update_file): Use it instead of printf. + +Fri Apr 19 05:52:45 1991 Roland McGrath (roland at churchy.gnu.ai.mit.edu) + + * main.c (main): When there are no targets, if there were no + makefiles, print a different error message, which mentions makefiles. + +Tue Apr 16 03:22:45 1991 Roland McGrath (roland at geech.gnu.ai.mit.edu) + + * remake.c (update_file): Print "nothing to be done" instead of "is + up to date" if FILE->cmds == 0. + + * job.c [!WIFEXITED]: Define if not already defined. + +Thu Apr 11 18:00:50 1991 Roland McGrath (roland at wookumz.gnu.ai.mit.edu) + + * arscan.c (ar_name_equal): Fixed truncation comparison. + +Tue Apr 2 16:17:35 1991 Roland McGrath (roland at churchy.gnu.ai.mit.edu) + + * glob.c: Use common version from djm. + * dir.c: Snarfed #ifdef mess for or whatever from glob.c. + (dir_file_exists_p): Ignore directory entries with d_ino==0. + +Mon Apr 1 20:49:45 1991 Roland McGrath (roland at albert.gnu.ai.mit.edu) + + * Version 3.59.4. + +Fri Mar 29 19:16:18 1991 Roland McGrath (roland at albert.gnu.ai.mit.edu) + + * job.c (free_child): Free CHILD->environment and its elts. + +Sat Mar 23 14:08:09 1991 Roland McGrath (roland at albert.gnu.ai.mit.edu) + + * read.c (read_makefile): Don't ignore lines containing only + comments if they start with a tab. Such lines should be passed to + the shell for it to decide about the comments. + + * job.c (free_child): Free CHILD->command_lines and its elts, not + CHILD->commands (which is obsolete). + * job.h, job.c: Remove obsolete `commands' member of `struct child'. + +Sun Mar 17 18:40:53 1991 Roland McGrath (roland at albert.ai.mit.edu) + + * remake.c (update_file): Print a msg for a top-level up-to-date + phony target (a different one than for a real file). + + * read.c (conditional_line): Boundary check so we don't check the + value of the -1th elt of the stack (which is bogus). + +Sat Mar 16 16:58:47 1991 Roland McGrath (roland at albert.ai.mit.edu) + + * read.c (conditional_line): Don't evaluate an if* when we're + already ignoring. Instead, just push a new level, with a value of + 1, to keep ignoring. + +Tue Mar 12 00:16:52 1991 Roland McGrath (roland at geech.ai.mit.edu) + + * Version 3.59.3. + +Mon Mar 11 23:56:57 1991 Roland McGrath (roland at geech.ai.mit.edu) + + * job.c (construct_command_argv_internal): Quote backslashes + when building the shell -c line. + +Fri Mar 8 01:40:18 1991 Roland McGrath (roland at geech.ai.mit.edu) + + * job.c (exec_command): Call user_access rather than setgid(getgid()). + + * misc.c (remove_comments): Renamed from collapse_line; took out + collapse_continuations call. + * make.h: Change decl. + * read.c (read_makefile): Collapse continuations on the line buffer + immediately after reading it. Call remove_comments rather than + collapse_line (which is now defunct). + +Thu Feb 21 18:06:51 1991 Roland McGrath (mcgrath at cygint.cygnus.com) + + * misc.c (user_access, make_access): New fns to toggle btwn permissions + for user data (files and spawning children), and permissions for make + (for taking the load average, mostly). + * make.h: Declare them. + * job.c (start_job): Call make_access before wait_to_start_job, and + user_access after. + * main.c (main): Call user_access before doing much. + +Mon Feb 3 15:02:03 1991 Roland McGrath (roland at albert.ai.mit.edu) + + * Version 3.59.2. + +Tue Jan 29 20:30:50 1991 Roland McGrath (roland at cygint.cygnus.com) + + * read.c (read_all_makefiles): Use allocated_variable_expand to expand + `$(MAKEFILES)', since the results are used across calls to + read_makefile, which could clobber them. + +Wed Jan 23 00:24:10 1991 Roland McGrath (roland at cygint.cygnus.com) + + * main.c (main): Call install_default_implicit_rules after reading + makefiles, not before. + * default.c (install_default_implicit_rules): If a suffix-rule file + entry has cmds, don't give it any from default_suffix_rules. + +Fri Jan 17 17:39:49 1991 Roland McGrath (roland at albert.ai.mit.edu) + + * arscan.c: Added support for AIX archives. + + * remake.c: Don't include ar.h. + * main.c: Removed unused atol decl. + * arscan.c (ar_scan): Declare arg FUNCTION to return long int. + * ar.c (ar_touch): Don't perror for an invalid archive. + * make.h: Declare lseek as long int. + + * job.c [hpux]: Define getdtablesize a la USG. + +Sun Jan 12 21:08:34 1991 Roland McGrath (roland at albert.ai.mit.edu) + + * Version 3.59.1. + +Fri Jan 10 03:48:08 1991 Roland McGrath (roland at albert.ai.mit.edu) + + * job.c (search_path): Take new arg, place to put full pathname (rather + than mallocing it). + (exec_command): Pass it, using auto storage. + + * main.c (print_version): Updated copyright years. + +Wed Jan 8 19:46:19 1991 Roland McGrath (roland at albert.ai.mit.edu) + + * job.c [_POSIX_SOURCE]: Just #include , and define macro + WAIT_NOHANG in terms of waitpid. + [!_POSIX_SOURCE && (HAVE_SYS_WAIT || !USG)]: Don't #include + (make.h does). + Define macro WAIT_NOHANG in terms of wait3. + (child_handler): #ifdef on WAIT_NOHANG, not HAVE_SYS_WAIT || !USG. + Use WAIT_NOHANG macro instead of wait3. + + * file.h (struct file.command_state): Remove unused elt. + +Wed Dec 26 18:10:26 1990 Roland McGrath (roland at albert.ai.mit.edu) + + * commands.c (set_file_variables): If FILE got its commands from + .DEFAULT, make $< == $@ (4.3 BSD/POSIX.2d11 compat). + +Mon Dec 24 17:36:27 1990 Roland McGrath (roland at albert.ai.mit.edu) + + * default.c (default_variables): Rename 2nd LINK.s defn to LINK.S. + +Fri Dec 14 15:05:25 1990 Roland McGrath (roland at albert.ai.mit.edu) + + * vpath.c (selective_vpath_search): Check for makefile-mentioned before + checking for actual existence. The old order loses if the containing + directory doesn't exist (but a rule might make it). + + * make.h [__GNUC__]: Don't #define alloca if already #define'd. + + * rule.c (convert_to_pattern): Don't look at the target constructed for + the empty rule when making the null-suffix rule. Construct it over + again, since the former may have been freed already. + +Thu Dec 13 17:21:03 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * make.h [__GNU_LIBRARY__]: Include to get random fn decls. + +Wed Dec 12 17:12:59 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * make.h, arscan.c, glob.c: Only include #ifdef USG. + + * variable.c (define_variable_in_set): Replace env_overrides check that + wasn't really redundant (undoing Sep 28 change). Add comment saying + why this check is necessary. + + * job.c, main.c [DGUX]: Needs siglist like USG. + +Mon Dec 11 01:19:29 1990 Roland McGrath (roland at albert.ai.mit.edu) + + * default.c [M_XENIX]: For rules that are different for Xenix, use the + generic Unix version #ifdef __GNUC__. + + * main.c [M_XENIX]: Use USGr3-style setvbuf call. + + * read.c (find_percent): Do backslash folding correctly, not leaving + extra crud on the end of the string. + +Sun Dec 10 21:48:36 1990 Roland McGrath (roland at albert.ai.mit.edu) + + * job.c: Don't declare wait3 if it's #defined. + + * GNUmakefile, compatMakefile, make.texinfo: Change make-info + to make.info. + +Thu Dec 7 21:20:01 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * make.h [STDC_HEADERS || __GNU_LIBRARY__ || _POSIX_SOURCE]: Use + ANSI and names for str/mem functions. + Use to declare misc fns rather than explicit decls. + [_POSIX_SOURCE]: Don't declare kill ( will). + Include before because some braindead + nonconformant 1003.1 implementation needs it. + * misc.c: Don't declare malloc, realloc. Do it in make.h. + * arscan.c, glob.c: Use sequence for string fns from make.h verbatim. + * make.h (S_ISDIR, S_ISREG): Declare if necessary. + * commands.c (delete_child_targets), job.c (search_path), read.c + (construct_include_path): Use S_ISfoo(m) instead of + (m & S_IFMT) == S_IFfoo. + * dir.c, glob.c [_POSIX_SOURCE]: Use dirent. + +Wed Nov 29 22:53:32 1990 Roland McGrath (roland at geech.ai.mit.edu) + + * Version 3.59. + +Tue Nov 28 16:00:04 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * arscan.c (ar_name_equal) [APOLLO]: Don't do `.o' hacking. On Apollos + the full file name is elsewhere, and there is no length restriction (or + so I'm told). + +Thu Nov 23 17:33:11 1990 Roland McGrath (roland at albert.ai.mit.edu) + + * load.c [hp300 && BSD] (LDAV_CVT): Define for this system. + +Tue Nov 21 07:58:40 1990 Roland McGrath (roland at albert.ai.mit.edu) + + * read.c (record_files): Fix trivial bug with deciding to free storage + for a file name. + +Thu Nov 16 06:21:38 1990 Roland McGrath (roland at geech.ai.mit.edu) + + * compatMakefile ($(bindir)/make): Install it setgid kmem. + +Thu Nov 1 16:12:55 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * GNUmakefile (make-*.tar.Z): Use `h' option to tar (dereference + symlinks), to grab texinfo.tex from wherever it lives. + +Tue Oct 30 16:15:20 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * Version 3.58.13. + +Fri Oct 26 14:33:34 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * GNUmakefile: make-*.tar.Z: Include texinfo.tex. + +Tue Oct 23 19:34:33 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * main.c (define_makeflags): When there are no flags to write, make + sure the array has two leading nulls, since `MAKEFLAGS' is defined from + &flags[1]. + + * main.c (default_keep_going_flag): New variable (constant one). + (command_switches: -k, -S): Use above for default value. + (define_makeflags): Only write flag/flag_off switches if they are on, + and either there is no default value, or they are not the default. + +Mon Oct 22 16:14:44 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * main.c (struct command_switch): New member `no_makefile'. + (command_switches: -n, -q, -t): Set no_makefile == 1. + (define_makeflags): Take new arg MAKEFILE: if nonzero, don't use + options whose `no_makefile' flags are set. + (main): Call define_makeflags with MAKEFILE==1 before remaking + makefiles, and again with MAKEFILE==0 before remaking goals. + +Tue Oct 2 17:16:45 1990 Roland McGrath (roland at geech.ai.mit.edu) + + * Version 3.58.12. + +Mon Oct 1 15:43:23 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * arscan.c [HPUX]: Use PORTAR==1 format. + +Sat Sep 29 16:38:05 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * make.h, remake.c, arscan.c: Don't declare `open'. + +Fri Sep 28 04:46:23 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * variable.c (define_variable_in_set): Remove redundant -e check. + +Wed Sep 26 00:28:59 1990 Roland McGrath (roland at geech.ai.mit.edu) + + * job.c (start_job): Set RECURSIVE from the right elt of + CHILD->file->cmds->lines_recurse. + + * commands.c (chop_commands): Don't botch the line count for allocating + CMDS->lines_recurse. + + * Version 3.58.11. + + * job.c (start_job): Don't always increment CHILD->command_line! Only + do it when CHILD->command_ptr has run out! (Dumb bug. Sigh.) + +Thu Sep 20 02:18:51 1990 Roland McGrath (roland at geech.ai.mit.edu) + + * GNUmakefile [ARCH]: Give explicit rule for remote.{c,dep} to use + variable `REMOTE' for more flags. + ($(prog)): Link in $(LOADLIBES). + +Wed Sep 19 02:30:36 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * commands.h (struct commands): New member `ncommand_lines', the number + of elts in `command_lines' et al. + * commands.c (chop_commands): Set `ncommand_lines' elt of CMDS, and + don't put a nil pointer at the end of `command_lines'. + * job.h (struct child): New member `command_lines' to hold + variable-expanded command lines. + * job.c (new_job): Store expanded command lines in `command_lines' + member of new child. Don't clobber FILE->cmds. + (start_job): Use CHILD->command_lines in place of + CHILD->file->cmds->command_lines. + + * variable.h, variable.c, job.c, expand.c: Undo yesterday's change, + which is no longer necessary since we have cleverly avoided the issue. + + * job.c (start_job): Don't variable-expand each command line. + (new_job): Do them all here, storing the expansions in the array. + +Tue Sep 18 01:23:13 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * variable.h (struct variable): Remove `expanding' member. + * variable.c (define_variable_in_set): Don't initialize it. + * expand.c (struct variable_expanding): New type, a linked list + containing `struct variable' pointers. + (variables_expanding): New variable, the chain of variables currently + being expanded. + (recursively_expand): Don't test and set `expanding' member. + Instead, run through the `variables_expanding' chain looking for a link + referring to V to find self-reference. Add a new link to the chain, + describing V, before recursive expansion, and pop it off afterward. + * job.c (child_handler): Save `variables_expanding' and clear it before + calling start_job, and restore it afterward. This avoids major lossage + when the SIGCHLD comes in the middle of variable expansion. + +Mon Sep 17 14:46:26 1990 Roland McGrath (roland at geech.ai.mit.edu) + + * job.c, commands.c: Don't define sigmask. + * make.h: Put it here instead. + + * variable.c (target_environment): If `.NOEXPORT' was specified as a + target, only export command-line and environment variables, and + file-origin variables that were in the original environment. + + * make.man: Add missing ?roff control for `-I' option description. + +Thu Sep 13 14:10:02 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * load.c [UMAX]: Move #include to [not UMAX_43]. + +Wed Sep 12 15:10:15 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * expand.c (recursively_expand): Don't use `reading_filename' and + `reading_lineno_ptr' if they're nil. + +Thu Aug 30 17:32:50 1990 Roland McGrath (roland at geech) + + * Version 3.58.10. + +Tue Aug 28 04:06:29 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * job.c [USG] (unknown_children_possible): New variable, set nonzero + when it's possible for children not in the `children' chain to die. + (block_signals) [USG]: Set it. + (unblock_signals) [USG]: Clear it. + (child_handler) [USG]: Don't complain about unknown children if + `unknown_children_possible' is set. + + * read.c (do_define): Make sure there's enough space for the newline, + so we don't write off the end of allocated space. + + * arscan.c (ar_name_equal): Fixed to work when MEM is AR_NAMELEN-1 but + NAME is not the same length. + +Sat Aug 25 16:17:14 1990 Roland McGrath (roland at geech) + + * job.c (construct_command_argv_internal): Use a static char array for + a constant, since old C has no auto aggregate initializers. + +Thu Aug 23 16:11:03 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * job.c (search_path): If PATH is nil or "" use a default path. + +Wed Aug 22 01:05:32 1990 Roland McGrath (roland at churchy.ai.mit.edu) + + * Version 3.58.9. + + * job.c (exec_command): Don't take PATH and SHELL args. Get them from + ENVP. + (child_execute_job): Don't take FILE arg, and don't pass path and shell + to exec_command. + (start_job): Don't pass FILE arg to child_execute_job. + * function.c (expand_function: `shell'): Ditto. + * main.c (main): Don't pass path and shell to exec_command. + +Fri Aug 17 23:17:27 1990 Roland McGrath (roland at geech) + + * job.c (construct_command_argv_internal): New fn broken out of + construct_command_argv. Takes strings SHELL and IFS instead of doing + variable expansion for them. Recurse to make an argv for SHELL, + passing SHELL==0. When SHELL==0, don't recurse for shell argv; make a + simple one using /bin/sh. + (construct_command_argv): Do the variable expansions and call above. + +Thu Aug 16 19:03:14 1990 Roland McGrath (roland at geech) + + * read.c (multi_glob): For ~USER/FILE, if USER isn't found, don't + change the file name at all. + +Tue Aug 7 18:33:28 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * function.c (expand_function: `suffix'/`notdir'): Don't kill the last + space if we never wrote one. + + * function.c (expand_function: `suffix'): Retain the dot, like the + documentation says. + +Mon Aug 6 14:35:06 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.58.8. + + * main.c (decode_switches): For positive_int and floating cases, move + SW past the arg (and don't set it to ""), so another switch can follow. + +Fri Aug 3 00:43:15 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * job.c (child_execute_job): Use unblock_signals instead of + push_signals_blocked_p (0). + + * main.c (fatal_signal_mask): New variable, mask of signals caught with + fatal_error_signal. + (main): Set it. + * job.c ({block,unblock}_children): Renamed to {block,unblock}_signals. + Block/unblock both child signal and signals in fatal_signal_mask. + (children_blocked_p_{stack,max,depth}, {push,pop}_children_blocked_p): + Renamed from children to signals. Use {block,unblock}_signals instead + of {block,unblock}_children. + * commands.c (fatal_error_signal), job.c (wait_for_children, new_job, + child_execute_job, main, log_working_directory), function.c + (expand_function: `shell'), job.h: Rename {push,pop}_children_blocked_p + to {push,pop}_signals_blocked_p. + * job.c (child_handler): Call {block,unblock}_signals instead of just + {block,unblock}_remote_children. We need to block the fatal signals. + +Thu Aug 2 22:41:06 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * main.c, function.c: Fixed typos in comments. + + * file.c (print_file_data_base): Fix computation of avg files/bucket. + +Tue Jul 31 22:11:14 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.58.7. + +Wed Jul 25 16:32:38 1990 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * arscan.c (ar_name_equal): Fixed to really do it right. + (ar_member_pos): Fixed order of args. + * ar.c (ar_member_date_1): Ditto. + +Fri Jul 20 15:30:26 1990 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * arscan.c (ar_name_equal): Rewritten. Accounts for a possible + trailing slash in MEM. + + * remake.c (f_mtime): Keep track of whether ARNAME is used and free it + if not. Also free MEMNAME. + * ar.c (ar_member_date, ar_touch): Ditto. + + * arscan.c (arscan) [HPUX or hpux]: Treat same as USGr3 PORTAR==1. + + * make.h: If NSIG is not defined, but _NSIG is, #define NSIG _NSIG. + + * compatMakefile: Don't use $* in explicit rules. + + * default.c (default_variables: "PREPROCESS.S"): Include $(CPPFLAGS). + + * remake.c (f_mtime): If FILE is an ar ref, get the member modtime. + + * function.c (string_glob): Terminate the string properly when it's + empty. + +Wed Jul 18 11:26:56 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.58.6. + + * commands.c (set_file_variables): Fixed computation for ^F/?F elt len. + +Sat Jul 14 13:41:24 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * job.c (construct_command_argv): Always use + allocated_variable_expand_for_file instead of variable_expand_for_file + because we might be called from inside a variable expansion (for the + `shell' function). + + * function.c (expand_function: `shell'): Free the arglist's storage + correctly. construct_command_argv only allocates ARGV and ARGV[0]. + + * job.c (children_blocked_p_idx): Renamed to children_blocked_p_depth. + (push_children_blocked_p, pop_children_blocked_p): Use ..._depth + instead of ..._idx, and do it right! + +Wed Jul 11 15:35:43 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * make.h (SIGNAL): New macro to replace `signal' calls. Does arg and + ret value casts to (void *) #ifdef __STDC__ to avoid conflicts btwn + ANSI and BSD `signal' and handler types. + * main.c (main), job.c (child_handler): Use it. + +Fri Jul 6 00:00:38 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * ar.c (ar_member_date, ar_touch): Pass 2nd arg to f_mtime. + + * read.c (read_makefile): Search the include path for MAKEFILES + variable makefiles (TYPE == 1), like it says in the manual. + + * file.h (struct file), main.c (struct command_switch): Remove trailing + commas from enums. + + * commands.c (execute_file_commands): Remove unused variables. + * commands.h: Declare chop_commands. + * make.h: Declare uniquize_deps. + * main.c (main): Remove unused variable. + (decode_switches): Remove unused label. + * remake.c: Include "ar.h" for ar_parse_name decl. + * implicit.c (try_implicit_rule): Remove unused variable. + * function.c (expand_function: `shell'): Declare fork, pipe. + * ar.c: Declare ar_name_equal. + + * GNUmakefile: If using gcc, add warning flags to CFLAGS. + + * remake.c: Remove decl of ar_member_date, since it's done in make.h. + + * remake.c (f_mtime): For ar refs, allow the archive to be found via + VPATH search if we're searching, and change the ar ref accordingly. + + * ar.c (ar_parse_name): New global fn to parse archive-member + references into the archive and member names. + (ar_member_date, ar_touch): Use it. + * make.h: Declare it. + + * remake.c (f_mtime): After doing rename_file, do check_renamed instead + of assuming rename_file will always set FILE->renamed (which it won't). + + * vpath.c (selective_vpath_search): Only accept prospective files that + don't actually exist yet are mentioned in a makefile if the file we are + searching for isn't a target. + +Wed Jul 4 04:11:55 1990 Roland McGrath (mcgrath at helen.Berkeley.EDU) + + * remake.c (update_goal_chain): Do check_renamed after calling + file_mtime. + (check_dep): Ditto after update_file. + + * file.c (rename_file): Prettied up long message for merging cmds. + + * remake.c (update_file_1): Get each dep file's modtime, and allow for + it being renamed, before checking for a circular dep, since a renaming + may have introduced one. + +Tue Jul 3 18:15:01 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * ar.c (ar_touch): Don't free ARNAME since enter_file holds onto the + storage. + + * function.c (string_glob): Don't leave a trailing space. + + * read.c (do_define): Allow leading whitespace before `endef'. + +Mon Jul 2 14:10:16 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * implicit.c (pattern_search): No longer take NAME arg. Instead take + ARCHIVE flag. If ARCHIVE is nonzero, FILE->name is of the form + "LIB(MEMBER)"; rule for "(MEMBER)" is searched for, and LASTSLASH is + set to nil. Since NAME was only non-nil when it was the archive member + name passed by try_implicit_rule, this change easily allows turning off + LASTSLASH checking for archive members without excessive kludgery. + (try_implicit_rule): Pass ARCHIVE flag instead of file name. + + * Version 3.58.5. + + * commands./c (set_file_variables): Don't kill last char of $(^D) elts. + +Sat Jun 30 00:53:38 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * ar.c (ar_member_date): Don't free ARNAME since enter_file holds onto + the storage. + + * arscan.c (ar_scan) [sun386 && PORTAR == 1]: Treat like USGr3. + +Wed Jun 27 14:38:49 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * main.c (main): Put a newline on the debugging message when deciding + not to remake a makefile to avoid a possible loop. + Only decide not to remake makefiles that have commands (as well as + being targets and having no deps). + +Fri Jun 22 12:35:37 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * default.c (default_variables): Define `LINK.s' and `LINK.S'. + (default_suffix_rules): Define .S.o rule. + + * job.c (construct_command_argv): If we decide to go the slow route, + free all storage for the chopped args. + (start_job): Free the argument list's storage correctly. + construct_command_argv only allocates ARGV and ARGV[0]. + +Tue Jun 19 18:27:43 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.58.4. + +Fri Jun 15 21:12:10 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * glob.c: New version from ai-lab which doesn't do [^abc]. + +Thu Jun 7 00:30:46 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * dir.c: Copied dirent vs direct et al mess from glob.c. + + * glob.c: Replaced with updated version from djm. + * glob.c: Check macro DIRENT instead of _POSIX_SOURCE for . + __GNU_LIBRARY__ implies DIRENT and STDC_HEADERS. + +Thu May 31 22:19:49 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * vpath.c (vpath_search): Don't stop the loop if a pattern matches but + the search fails. All matching patterns have their paths searched + (like it says in the manual). + + * make.texinfo (Rules: Directory Search: Selective Search): Say that + multiple `vpath' directives with the same pattern DO accumulate, not + supersede earlier ones. + + * vpath.c (print_vpath_data_base): Increment the count of vpaths on + each loop iteration, rather than letting it stay zero. + + * Version 3.58.3. + + * job.c (block_children, unblock_children): Made static. + (push_children_blocked_p, pop_children_blocked_p): New functions to + push and pop whether children are blocked or not. + * job.h: Declare push_children_blocked_p, pop_children_blocked_p and + not block_children, unblock_children. + * commands.c (fatal_error_signal), job.c (wait_for_children, new_job, + child_execute_job), main.c (main, log_working_directory): Use sequences + of push_children_blocked_p (1) and pop_children_blocked_p () instead of + explicitly blocking and unblocking children. + * function.c (expand_function: `shell'): Don't unblock children. The + push-pop sequence in wait_for_children makes it unnecessary. + +Tue May 29 21:30:00 1990 Roland McGrath (mcgrath at helen.Berkeley.EDU) + + * read.c (do_define): Don't include the last newline in the definition. + + * function.c (expand_function: `shell'): Call construct_command_argv + before forking and don't fork if it returns nil. Free the argument + list's storage before finishing. + + * job.c (start_job): Free the storage for the child's argument list + in the parent side of the fork after the child has been spawned. + + * job.c (start_job): If construct_command_argv returns nil, go to the + next command line. + + * job.c (construct_command_argv): Use the shell if the command contains + an unterminated quote. + +Wed May 23 19:54:10 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.58.2. + + * read.c (read_makefile): Parse "override define" correctly. + +Thu May 17 15:25:58 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * arscan.c [USG]: Don't declare memcpy and memcmp. should + do this anyway (and lack of declarations is harmless). + + * remote-customs.c: Renamed to remote-cstms.c for System V. + * remote.c [CUSTOMS]: Changed accordingly. + +Sun May 13 14:38:39 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * GNUmakefile: Use same cmds for doc tar.Z as for dist tar.Z (so the + contents go in make-N.NN). + +Thu Apr 26 19:33:25 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * Version 3.58.1. + +Wed Apr 25 20:27:52 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * job.c (init_siglist): Don't do SIGUSR1 and SIGUSR2 if they are the + same as SIGIO and SIGURG (true on Cray). + +Tue Apr 24 20:26:41 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * arscan.c (ar_scan): Do behavior for PORTAR == 1 and USGr3 also + #ifdef APOLLO. + +Wed Apr 11 10:00:39 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * job.c (exec_command): Set the effective GID to the real GID. Somehow + this code got lost. + + * implicit.c (pattern_search): Use the right index variable when + seeing if we need to expand FILE->also_make. + +Sun Mar 4 09:18:58 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * Version 3.58.0. + + * remake.c (remake_file): Treat non-targets without commands under -t + the same as anything else without commands. + +Sat Feb 24 17:46:04 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * default.c (default_variables: PREPROCESS.S): Removed $< from defn. + + * main.c (main): Ignore arguments that are the empty string, rather + than feeding them to enter_file and barfing therein. + +Wed Feb 14 16:28:37 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * main.c (main): Call construct_include_path after doing chdirs. + +Thu Feb 8 13:43:44 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * Version 3.58. + +Sat Feb 3 22:06:55 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * Version 3.57.7. + + * make.texinfo (Implicit: Catalogue of Rules): For RCS, noted that + working files are never overwritten by the default rule. + +Thu Feb 1 17:27:54 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * rule.c (count_implicit_rule_limits): Redid loop control to not run + twice on freed rules. + + * GNUmakefile: Made `.dep' files be architecture-specific too. + + * main.c (main, log_working_directory) [USG]: Block children around + calls to `getwd' (actually `getcwd' on USG), because that function + sometimes spawns a child running /bin/pwd on USG. + +Tue Jan 30 14:02:50 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * function.c (subst_expand): Pay attention to SUFFIX_ONLY, putz. + +Wed Jan 24 21:03:29 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * make.man: Fixed repeated word. + + * make.texinfo (Missing): Reworded a buggy sentence. + +Mon Jan 22 12:39:22 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * main.c (print_version): Added 1990 to copyright notice. + + * Version 3.57.6. + +Sat Jan 20 11:52:01 1990 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * file.c (rename_file): Don't free the storage for the old name, since + it might not have been malloc'd. + + * job.c (construct_command_argv): Call + allocated_variable_expand_for_file instead of variable_expand_for_file + to expand `$(SHELL)'. + + * make.texinfo (Bugs): Change address from roland@wheaties.ai.mit.edu + to roland@prep.ai.mit.edu. + +Tue Jan 16 19:22:33 1990 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * Version 3.57.5. + +Sun Jan 14 16:48:01 1990 Roland McGrath (mcgrath at helen.Berkeley.EDU) + + * job.c (start_job): Only call wait_to_start_job for the first command + line in each sequence. + +Thu Jan 4 14:27:20 1990 Roland McGrath (mcgrath at helen.Berkeley.EDU) + + * load.c [LDAV_BASED] (wait_to_start_job): Loop while job_slots_used > + 0, not > 1. + + * job.c (search_path): Don't return a pointer to local storage. + Allocate data space for the pathname instead. + + * function.c (expand_function: `shell'): Don't write garbage if the + child wrote no output. + +Wed Jan 3 15:28:30 1990 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.57.4. + + * file.h (struct file): New member `renamed', a `struct file *' that is + the place this file has been renamed to (or nil). + (check_renamed): Macro to check for a file having been renamed. + Dereferences the renaming and sets the given variable. + * file.c (rename_file): Completely rewritten. Renames in place if + possible, or moves FILE to a different hash bucket if there is no + existing file with the new name. If there is an existing file with the + new name, FILE is merged into it and FILE->renamed is set to point to + it. + * variable.c (merge_variable_sets): New fn to merge two variable sets. + (merge_variable_set_lists): New fn to merge two variable set lists. + * variable.h: Declare merge_variable_set_lists. + * remake.c (update_file_1, check_dep): Run `check_renamed' after + calling file_mtime, check_dep. + (update_file): Same after update_file_1. + (update_goal_chain, update_file_1, check_dep): Same after update_file. + + * read.c (uniquize_deps): New fn, broken out of record_files, to remove + duplicate deps from a chain. + (record_files): Use it. + * implicit.c (pattern_search): Use uniquize_deps. + + * file.h (file_mtime_1): New macro, like file_mtime, but take second + arg, passed to f_mtime. + (file_mtime): Implement as file_mtime_1 (file, 1). + (file_mtime_no_search): New macro: file_mtime (file, 0). + * remake.c (f_mtime): Take new arg SEARCH. Only do VPATH and `-lNAME' + searching if it is nonzero. + * main.c (main): Use file_mtime_no_search for makefiles. + * remake.c (update_goal_chain): Use file_mtime_no_search if MAKEFILES. + + * main.c (printed_version): New variable, init'd to zero. + (print_version): Set it to nonzero before returning. + (die): If -v and !printed_version, call print_version before clean up + and death. + + * main.c (log_working_directory): Keep track of whether or not the + "Entering" message has been printed, and return without printing the + "Leaving" message if not. + + * main.c (decode_switches): Don't complain about missing args before + checking for a noarg_value elt in the command_switch structure. + +Tue Jan 2 15:41:08 1990 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * make.texinfo (Commands: Recursion: Options/Recursion): Document + special case of -j. + + * make.texinfo, main.c, job.c: Changed copyright notices to include + 1990. + + * make.texinfo (Top): Fixed introductory paragraph, which said that + `make' itself (instead of the manual) has various chapters. + (Variables: Advanced: Substitution Refs): When pxref'ing about + `patsubst', use node `Text Functions', not `Functions'. + Add an xref about `patsubst' after description of $(var:a%b=c%d). + (Functions: Syntax of Functions): Explain why mixing delimiters in + function/var refs is unwise. Clarify fn arg evaluation order. + (Options): Reworded sentence about `-e'. + (Implicit: Implicit Variables): Don't say `RM' is unused. + Say the dflt values for the flag vars is empty unless otherwise noted, + since some have defaults. + (Implicit: Pattern Rules: Pattern Examples): Clarified use of $< and $@ + in first example. + (Implicit: Last Resort): Don't say the .DEFAULT example creates files + "silently". It's automatic, but not silent. + (Implicit: Search Algorithm): Fixed confusing ungrammatical sentence + for item 5.1. + (Archives: Archive Update): Added missing `next' pointer. + (Archives: Archive Symbols): Note that GNU `ar' deals with this + automatically. + + * job.c (search_path): New fn, to search for an executable file in a + search path (broken out of exec_command). + (exec_command): Take fourth arg, the shell program to use (if + necessary). Use search_path for the program, and the shell program. + Pass args "file args ..." to shell program (with no -c), where FILE is + the full pathname of the program (script) to be run. + (child_execute_job): Pass shell program to exec_command. + * main.c (main): Ditto. + + * main.c (main): Don't write a message if exec_command returns, because + it will never return. + +Fri Dec 22 16:19:58 1989 Roland McGrath (mcgrath at hecuba.Berkeley.EDU) + + * default.c (default_variables: "LINK.cc"): Use $(C++FLAGS) instead of + $(CFLAGS). + +Wed Dec 20 09:58:48 1989 Roland McGrath (mcgrath at hecuba.Berkeley.EDU) + + * job.c (new_job): If start_job set the child's `command_state' to + `cs_finished', call notice_finished_file. + +Sun Dec 17 19:45:41 1989 Roland McGrath (mcgrath at hecuba.Berkeley.EDU) + + * Version 3.57.3. + +Wed Dec 13 17:57:12 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * rule.c (convert_to_pattern): Accept files with dependencies as + suffix rules. + +Thu Nov 30 15:47:13 1989 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * Version 3.57.2. + + * function.c (expand_function: `shell'): Don't clobber BUFFER and then + try to free it. + + * remake.c (update_file_1): Took code to force remake of nonexistent + deps out of #if 0, and changed the test to nonexistent non-intermediate + deps. In version 4, I think removing this test completely will + implement the new feature that if a: b and b: c and c is newer than a, + b need not be remade. + +Sun Nov 26 16:12:41 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * compatMakefile (load.o, remote.o): Use $*.c instead of explicit file + names so that using VPATH works. + +Tue Nov 21 14:57:18 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.57.1. + +Fri Nov 10 03:28:40 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * remake.c (check_dep): Set *MUST_MAKE_PTR if FILE does not exist after + being updated. (The exact opposite test was here before; why???) + (update_file_1): Set a dep's `changed' member after updating it if it + is phony and has commands (because they will then always be executed). + +Thu Nov 9 13:47:12 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * load.c [UMAX]: #ifdef UMAX_43 include different headers for the + `inq_stats' call. + * compatMakefile (LOAD_AVG): Document UMAX_43. + + * Version 3.57.0. + + * commands.c (chop_commands): New function to chop commands into lines. + * job.c (new_job): Break that code out, and call chop_commands. + * remake.c (remake_file): Call chop_commands before looking at + FILE->cmds->any_recurse. + + * make.texinfo (Running: Goals): Don't say that the default target + won't be taken from an included makefile. + + * remake.c (update_file_1): #if 0 out setting MUST_MAKE if a dep + doesn't exist. + +Fri Nov 3 15:53:03 1989 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * Version 3.57. + + * variable.c (try_variable_definition): Don't calculate useless value. + + * main.c (define_makeflags): Fixed -j propagation. + + * commands.c (execute_file_commands): Removed unused variable. + +Sun Oct 29 11:11:15 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * commands.c (execute_file_commands): If the commands are empty, call + notice_finished_file before returning. + +Sat Oct 28 23:06:32 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * remake.c (update_file_1): Don't always update a target that has no + deps. Only do this for double-colon targets. + +Wed Oct 25 16:36:16 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * main.c (main) [hpux]: hpux == HPUX. + * compatMakefile (defines): Document that HPUX should be defined. + +Tue Oct 24 19:19:48 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.56.8. + + * job.c (exec_command): Fixed what mode bits are checked. + + * remake.c (update_file_1): "No cmds and no deps actually changed" + loses if ! FILE->is_target. + + * make.texinfo (Variables: Setting): Don't say that spaces after a + variable definition are ignored (since they aren't). + +Mon Oct 23 14:34:23 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.56.7. + + * remake.c (update_file_1): If, after being updated, any dependency + does not exist, remake the target. + + * remake.c (update_file_1): Always update if FILE has commands but no + deps. + + * commands.c (execute_file_commands): If we return early because there + are no commands, set FILE->updated. + +Thu Oct 19 18:47:37 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * arscan.c (ar_scan) [M_XENIX]: Don't run atoi or atol on the + `struct ar_hdr' members that are int or long int on Xenix. + +Sat Oct 14 10:43:03 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * arscan.c (ar_scan): Cosmetic clean ups. + (ar_name_equal): New function to compare names, handling truncated + member names and special `.o' truncation. + (ar_member_pos): Use ar_name_equal. + * ar.c (ar_member_date_1): Use ar_name_equal. + + * Version 3.56.6. + + * file.h (struct file): Made `update_status' a `short int', and moved + it before `command_state' so the bitfields can be packed better. + + * remake.c (files_remade): Made global. + (notice_finished_file): Don't increment files_remade. + * job.c (new_job): Do. + + * job.c (start_job): Don't return a value. Always set + CHILD->file->command_state to either cs_running or cs_finished. + (new_job, child_handler): Don't expect start_job to return a value. + Instead, look at the file's command_state. + + * commands.c (chop_commands): Merged into job.c (new_job). + * commands.h: Don't declare chop_commands. + + * job.c (start_job): Made static. + (new_job): New function to create a `struct child' and call start_job. + (free_child): New function to free a `struct child'. + (child_handler, new_job): Call it. + * job.h: Don't declare start_job. Do declare new_job. + * commands.c (execute_file_commands): Call new_job. + + * commands.c (execute_file_commands): Don't set FILE->update_status if + start_job fails. + + * function.c (expand_function): Don't use `reading_filename' and + `reading_lineno_ptr' if they're nil. + +Fri Oct 13 18:16:00 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * read.c (find_semicolon): New function to look for an unquoted ; not + preceded by an unquoted # in a string. + (read_makefile): Call it before expanding the line. If it finds a ;, + cut the line short there before expanding it. If not, call it again + after expanding. + + * commands.c (execute_file_commands): Don't check FILE->command_state. + We won't get called unless it's cs_not_started. + + * read.c (read_makefile): Call collapse_line on the variable-expanded + rule line after checking for ; and #. + + * job.c (start_job): When there are no more commands, always return 0. + * commands.c (execute_file_commands): Don't put the new child in the + `children' chain unless FILE->command_state is cs_running. + + * read.c (read_makefile): Rewrote ;-handling to only do it once (why + did I do it twice??) and to check for a # before the ;. + + * job.c (start_job): Set CHILD->file->update_status to 0 when we run + out of commands. Set it to 1 before returning failure. + (child_handler): Don't set C->file->update_status to 0 when start_job + returns success and commands are not running. + + * read.c (read_makefile): If there is a # before the ; for commands, + forget the ; and commands. + +Thu Oct 12 15:48:16 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * job.c (child_execute_job): Pass -c to the shell. + +Wed Oct 11 18:41:10 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.56.5. + + * main.c (define_makeflags): Cleaned up to keep better track of dashes + written, etc. + + * function.c (expand_function: `shell'): When converting newlines to + spaces in output, search with `index' calls rather than a simple loop. + + * main.c (main): Make sure stdout is line-buffered. + + * main.c (decode_switches): Always check for missing switch arg. + +Mon Oct 9 17:17:23 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.56.4. + +Sat Oct 7 00:32:25 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * commands.c (set_file_variables): #ifdef NO_ARCHIVES, still set $@ and + $%. + + * commands.c (set_file_variables): Include a trailing slash in the + directory variables (@D, etc.). + + * job.c (child_handler): Call notice_finished_file after changing a + child's state to `cs_finished'. + * remake.c (update_file_1): Don't call notice_finished_file if + FILE->command_state == cs_finished. + +Wed Oct 4 16:09:33 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.56.3. + +Tue Oct 3 21:09:51 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * read.c (read_all_makefiles): When setting elements of MAKEFILES from + the contents of read_makefiles, make sure we're using the right + element. + + * dir.c, glob.c [USGr3 || DIRENT]: Don't define d_ino as d_fileno. + + * Version 3.56.2. + + * remake.c (update_file_1): Return zero after calling remake_file if + FILE->command_state != cs_finished. Test update_status thoroughly. + + * commands.c (execute_file_commands): Don't call notice_finished_file. + + * remake.c (remake_file): Return immediately after calling + execute_file_commands. + +Sat Sep 30 14:57:05 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.56.1 (alpha). + + * file.h (struct file): Made `update_status' not be a bitfield, since + some broken compilers don't handle it right. + + * function.c (expand_function: `join'): Don't clobber the pointers and + then try to free them. + + * job.c (exec_command): Fixed & vs = precedence problem. + +Thu Sep 28 17:29:56 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * remake.c (update_file_1): Fixed typo in debugging output. + + * remake.c (library_file_mtime): Search for /usr/local/lib/libLIB.a + after /usr/lib/libLIB.a. + +Tue Sep 26 16:07:58 1989 Roland McGrath (mcgrath at helen.Berkeley.EDU) + + * read.c (conditional_line): For `ifeq (a, b)', swallow space after the + comma. + +Sun Sep 24 13:25:32 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * function.c (patsubst_function): If BY_WORD and the match is not a + full word, update the text pointer correctly. + + * function.c (expand_function: `word'): Don't lose track of the second + arg's expansion and free something else instead. + +Fri Sep 22 16:15:29 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.56. + +Thu Sep 21 14:28:42 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * main.c (main): Make an array of the mtimes of the makefiles before + updating them, and compare their file_mtimes against this later. Don't + re-exec if a makefile was successfully updated but didn't change. If a + makefile failed to be remade and no longer exists, die. If a makefile + failed to be remade, but changed anyway, re-exec. If a makefile failed + to be remade, but is unchanged, continue on. + +Wed Sep 20 18:02:07 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.55.6. + + * implicit.c (pattern_search): Maintain an array CHECK_LASTSLASH of the + CHECK_LASTSLASH flag values used to match each member of TRYRULES. + When making FILE->stem, if CHECKED_LASTSLASH[FOUNDRULE], prepend the + part of FILENAME before LASTSLASH. + +Tue Sep 19 17:44:08 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * dir.c (dir_file_exists_p): Check for FILENAME being nil before + checking for it being "". + + * main.c (define_makeflags): Fixed test for whether a flag/flag_off + option was non-default. Also changed to generate a string that Unix + Make will grok (except for FP/int values and new flags). + + * job.c (child_execute_job): Don't use the shell's -c option. + Also fixed an off-by-one bug in the ARGV -> shell arg list copying. + +Mon Sep 18 15:17:31 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.55.5. + + * read.c (parse_file_seq): Check the beginning of the file name for a + `./', not the two chars after the end of the name (Q rather than P). + + * job.c (child_execute_job): Include all of ARGV in the arg list for + the shell. + + * main.c (define_makeflags): Don't include floating and positive_int + options in !PF. + + * job.c (exec_command): Set the effective gid to the real gid before + execing. + + * job.c (child_execute_job): Don't clobber the arg list when execing + the shell. + +Sun Sep 17 15:27:19 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * main.c (define_makeflags): Moved all the checking inside the switch. + + * load.c [LDAV_BASED] (load_average): When we can't get the load + average, return zero instead of running off the end. + + * file.c: Include variables.h. + * job.c: Declare dup2 and {block,unblock}_remote_children. + * file.h: Declare f_mtime. + * job.c: Don't declare construct_command_argv, since job.h does. + * function.c, main.c, load.c, remake.c: Include job.h. + * load.c [LDAV_BASED] (load_average): Declare nlist. + * variable.h: Declare print_file_variables. + * job.c [!USG]: Don't declare sigsetmask. + [!USG]: Declare getdtablesize. + Don't declare load_average. Do declare wait_to_start_job. + Declare vfork, gete[gu]id, execve. + * commands.c: Declare remote_kill, getpid. + * make.h: Declare kill, exit, sigblock, pipe, close, ctime, open, + lseek, read. + * make.h [not USG]: Declare sigsetmask. + * job.h: Declare wait_for_children and {block,unblock}_children. + + * dir.c (dir_file_exists_p): If FILENAME is nil, read in the whole + directory. + (find_directory): When we want to read in the whole directory, call + dir_file_exists_p with nil instead of "". + + * file.h (struct file), job.h (struct child), + variable.h (struct variable): Use bitfields for flags. + * make.h (ENUM_BITFIELD): If GCC or #ifdef ENUM_BITFIELDS, define as + :BITS, else empty. + * compatMakefile (defines): Document ENUM_BITFIELDS. + +Sat Sep 16 12:38:58 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.55.4 (alpha). + + * GNUmakefile (dist): Depend on default and doc. + + * load.c [LDAV_BASED]: Include rather than ; #ifdef + NLIST_NAME_UNION, use n_un.n_name instead of n_name. + * compatMakefile (LOAD_AVG): Document NLIST_NAME_UNION. + + * job.c [USG-ish]: Don't redefine WIF{SIGNALED,EXITED} if they're + already defined. + +Fri Sep 15 13:59:42 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * glob.c, dir.c [USGr3 or DIRENT]: If neither d_ino, nor d_fileno is + defined, define d_ino as d_fileno. + +Thu Sep 14 18:29:38 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * job.c: Don't declare exec_command static. + + * make.texinfo (Name Index): Changed title to include directives. + + * Version 3.55.3 (alpha). + + * make.texinfo (Running: Options): Document -e. + + * main.c (main): Always give imported environment variables origin + `o_env'. + * variable.c (define_variable_in_set): Under -e, if ORIGIN, or an + existing variable's origin, is `o_env', make it `o_env_override'. + + * load.c: Use the symbol KERNEL_FILE_NAME instead of KERNEL_FILE. + * compatMakefile: Changed the comment for `LOAD_AVG' accordingly. + +Thu Sep 7 16:46:26 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.55.2 (alpha). + + * variable.c (print_variable_set), rule.c (print_rule_data_base), + file.c (print_file_data_base): If NO_FLOAT is defined, don't use + floating-point for printing statistics. + * compatMakefile (defines): Document NO_FLOAT. + + * make.h (HASH): New macro to add the hashing value of one char to a + variable.c. + * file.c (lookup_file, enter_file, rename_file): Use it. + * dir.c (find_directory, dir_file_exists_p, file_impossible_p): Ditto. + * variable.c (define_variable_in_set, lookup_variable): Same here. + + * variable.c, file.c, dir.c: Don't define *_BUCKETS if they are already + defined. + + * compatMakefile (defines): Added comment about defining NO_ARCHIVES. + (ARCHIVES, ARCHIVES_SRC): New variables for {ar,arscan}.[oc]. + (objs, srcs): Use $(ARCHIVES) and $(ARCHIVES_SRC). + * commands.c (set_file_variables), dir.c (file_exists_p), + remake.c (touch_file, name_mtime), implicit.c (try_implicit_rule, + pattern_search), make.h: If NO_ARCHIVES is #defined, don't do any + archive stuff. + + * commands.c (set_file_variables): Don't kill the last char of + directory names in $([@*<%?^]D). + +Wed Sep 6 15:23:11 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * default.c (default_terminal_rules {%:: %,v}, {%:: RCS/%,v}): Don't + run co if the target exists. + + * glob.c (glob_match): [!xyz], rather than [^xyz], means none of [xyz]. + + * glob.c: Misc minor cosmetic changes. + +Tue Sep 5 14:49:56 1989 Roland McGrath (mcgrath at saffron.Berkeley.EDU) + + * load.c [LDAV_BASED] (load_average): Check for == -1, rather than < 0 + to see if lseek fails. On some systems, `avenrun' is at an offset > + (2**31)-1, and lseek succeeds, returning a negative value. + +Mon Sep 4 11:07:58 1989 Roland McGrath (mcgrath at saffron.Berkeley.EDU) + + * rule.c (new_pattern_rule): Return `int' instead of `void': nonzero if + the passed rule was used, zero if not. + (install_pattern_rule): Pay attention to the return from + new_pattern_rule, and don't set the rule's `terminal' flag or give it + commands unless it's used. + (create_pattern_rule): Same idea. + + * dir.c (find_directory): Removed unused variable. + + * commands.c (execute_file_commands): Removed unused variable. + + * read.c (record_files): Don't use NAME after freeing it. + +Sat Sep 2 00:33:19 1989 Roland McGrath (mcgrath at saffron.Berkeley.EDU) + + * Version 3.55.1 (alpha). + + * function.c (string_glob): Don't add spaces after file names that + aren't added. (Also means don't add spaces without checking the size + of the buffer.) + + * remake.c (update_goal_chain): Don't remove makefiles with cmds and no + deps from the chain. + * main.c (main): Do it here, before calling update_goal_chain. + + * remake.c (update_goal_chain): When updating fails, change STATUS even + if MAKEFILES is set. Also stop remaking when updating fails if not + under -k and MAKEFILES is not set. + + * remake.c (remake_file, update_file_1, notice_finished_file), + commands.c (execute_file_commands), make.h, commands.h: The functions + remake_file, notice_finished_file, and execute_file_commands no longer + return values, and their callers no longer expect values returned. + + * remake.c (notice_finished_file): Don't set FILE's modtime to now if + it is a non-target with no commands. + +Fri Sep 1 00:04:39 1989 Roland McGrath (mcgrath at saffron.Berkeley.EDU) + + * read.c (read_all_makefiles): After freeing each element on MAKEFILES, + replace it with the name stored in read_makefiles by read_makefile. + + * remake.c (update_file_1): Don't decide not to remake if FILE has no + cmds and no deps actually changed if FILE doesn't have any deps. + + * file.c (remove_intermediate): Remove precious files that also have + the `dontcare' flag set. + + * remake.c (update_file_1): Don't always remake if FILE has cmds but no + deps; only if FILE is double-colon. (I don't know why this should be + done for double-colon targets, but that's what Unix make does.) + + * load.c [LDAV_BASED] (load_average): Write error messages if the + various system calls fail. Keep track of if we've failed before. + The first time we fail, write a message saying -l won't be enforced. + The first time we succeed after having failed, write a message saying + -l will be enforced again. + + * remake.c [USG]: Don't #include + + * load.c [generic Unix LDAV_BASED]: #include #ifdef USG, + else instead. + + * job.c [USG && !USGr3 && !HAVE_DUP2]: Remove redundant + #include and declaration of `errno'. + [...] (dup2): Fixed so it won't always lose. + + * default.c (default_suffix_rules: .texinfo.dvi): Copy, rather than + move, the aux and index files, so the TeX run can use them. + + * compatMakefile: Remove redundant comment. + + * load.c [generic Unix LDAV_BASED]: Include instead of + , since the `struct nlist' declaration in varies + more than the one in . + (load_average): Use the `n_un.n_name' field of the `struct nlist', + since the declaration uses the union. + + * main.c (main): For the temporary files made for stdin makefiles, set + the `intermediate' and `dontcare' flags. + * file.c (remove_intermediates): Don't print any messages for files + whose `dontcare' flag is set. (The only files that will be + intermediate and `dontcare' will be the temporary files made for stdin + makefiles.) + + * job.c (exec_command): Made global. + * job.h: Declare it. + * main.c (main): Use exec_command when re-execing. + + * make.h: Declare environ. + * make.c: Don't. + + * job.c (child_execute_job): New function to perform everything done in + the child side of a fork (for a job or `shell' function). + (start_job): Call it. + * job.h: Declare construct_command_argv and child_execute_job. + * function.c (expand_function: `shell'): Use child_execute_job. + +Thu Aug 31 18:42:51 1989 Roland McGrath (mcgrath at saffron.Berkeley.EDU) + + * function.c (expand_function: `shell'): Remove a trailing newline + instead of turning it into a space. + + * main.c (main): Do init_siglist #ifdef HAVE_SIGLIST. + + * job.c [WTERMSIG || (USG && !HAVE_SYS_WAIT)]: Test each W* macro + separately and define all those that aren't defined. + +Sat Aug 26 15:13:21 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * ar.c (ar_name): Return zero for `(foo)'. + + * Version 3.55. + + * make.texinfo (Rules: Multiple Targets): Make this node's `next' + pointer point to `Static Pattern'. + * make.texinfo (Makefiles: MAKEFILES Variable): Make this node's `prev' + pointer point to `Makefile Names'. + + * make.1: Renamed to make.man. + * compatMakefile: Define `mandir' and `manext'. + (install): Depend on $(mandir)/make.$(manext). + ($(mandir)/make.$(manext)): Depend on make.man and copy it to $@. + ($(bindir)/make): Use `make' rather than $<; so Unix make can grok it. + +Thu Aug 24 03:35:48 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * variable.c (target_environment): Allow variables that start with + underscores. + +Wed Aug 23 22:50:32 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * variable.c (target_environment): Reject variables that don't start + with letters. + +Tue Aug 22 04:14:29 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * GNUmakefile (make-$(version).tar.Z): Put make.1 (the Unix manual + page) in the tar file. + + * variable.c (target_environment): Don't write variables with origin + o_default (i.e., ones from default.c). + * make.texinfo (Commands: Recursion: Variables/Recursion): Document + that default variables are not put in the environment. + + * remake.c (update_file_1): Remake all targets with commands but no + deps. + +Sat Aug 19 06:03:16 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * remake.c (update_file_1): In the final loop, set the deps' + `changed' members if they are newer than FILE. + + * remake.c (update_goal_chain): Under -d, print a message if we decide + not to remake a makefile so as to avoid a possible infinite loop. + +Fri Aug 18 20:30:14 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * remake.c (remake_file): Cleaned up. + + * commands.c (execute_file_commands): If the commands are empty, set + FILE->update_status to zero before returning. + + * remake.c (notice_finished_file): Set `last_mtime' fields to zero + instead of calling name_mtime; file_mtime will do that later if anybody + cares. + +Thu Aug 17 10:01:11 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * make.texinfo (Rules: Wildcards: Wildcard Examples): Give this node a + `prev' pointer. + + * Version 3.54.9 (alpha). + + * make.texinfo: Fixed some @nodes. + + * remake.c (check_dep): Don't set *MUST_MAKE_PTR if FILE doesn't exist + after running update_file. + + * remake.c (notice_finished_file): If FILE has no commands, pretend its + modtime is now. + + * remake.c (update_file_1): In the loops that call update_file on the + deps, compare modtimes before and after (unless deps are still being + made) and set the deps' `changed' members. Do not set the `changed' + members in the loop that prints the newer/older debugging messages. + * remake.c (update_file_1): If no deps changed and FILE has no + commands, decide it doesn't need remaking. + + * remake.c (update_file_1): Print a debugging message if we take + commands from default_file. + + * make.texinfo (Rules: Directory Search: Selective Search): Removed + note about warning for `vpath' with a constant pathname, since it isn't + warned about anymore. + + * remake.c (update_goal_chain): If MAKEFILES, remove makefiles which + are targets and have no deps. + * make.texinfo (Makefiles: Remaking Makefiles): Document that makefiles + will not be remade if they are targets but have no dependencies. + +Tue Aug 15 00:00:08 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) + + * remake.c (notice_finished_file): Increment files_remade for non-phony + files if they didn't exist before (even if they still don't). + + * job.c: Include and declare errno. + + * job.c (exec_command): If the execve fails with ENOEXEC (Exec format + error), return instead of exiting the child process. + + * job.c (start_job): In the child side, if exec_command fails, try + using the shell. + + * job.c (start_job): In the child side, call unblock_children instead + of sigsetmask. + + * remake.c (notice_finished_file): Under -n or -q, always increment + files_remade for non-phony files. + + * rule.c (intall_pattern_rule): Use find_percent. + + * vpath.c (vpath_search): Pass the `percent' members to + pattern_matches. + +Mon Aug 14 23:30:24 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) + + * vpath.c (struct vpath): New member `percent', to hold a pointer into + the pattern where the % is. + (construct_vpath_list): Call find_percent on the pattern and set the + new `percent' member. + * read.c (read_makefile): Don't run find_percent on `vpath' directive + patterns. + + * function.c (pattern_matches): Take new arg PERCENT, a pointer into + PATTERN where the % is. If PERCENT is nil, copy PATTERN into local + space and run find_percent on it. + (expand_function: `filter', `filter-out'): Pass new arg to + pattern_matches. + * read.c (record_files): Pass PATTERN_PERCENT to pattern_matches for + static pattern rules. Save the percent pointer into implicit rule + targets, and pass them to create_pattern_rule. + * rule.c (convert_to_pattern): Pass new arg to create_pattern_rule. + (create_pattern_rule): Take new arg TARGET_PERCENTS, nil or an array of + pointers into the corresponding elements of TARGETS, where the %s are. + +Sun Aug 13 00:29:19 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * Version 3.54.8. + + * README.templatate, README-doc.template: New files, turned into README + and README-doc to go into the two distribution tar files. + * GNUmakefile: Added a rule to edit the version number in + README.template and README-doc.template, producing README and + README-doc. + + * remake.c (update_goal_chain): If -n or -q is in effect for a + makefile, and it got updated, don't change STATUS, so we can still + return -1 (meaning nothing was done). This avoids an infinite loop on + "make -n Makefile". + +Sat Aug 12 23:14:24 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * remake.c (notice_finished_file): Treat -q the same as -n. + + * remake.c (update_goal_chain): Fixed handling of return from + update_file. If -n or -q is in effect, ignore it. + + * job.c (start_job): Don't test for -t. We should never get called in + that case. + +Fri Aug 11 04:09:14 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * function.c (expand_function): Removed unused variables. + (handle_function): Removed unused variable. + + * main.c (main): Removed unused variable. + +Wed Aug 9 09:37:10 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * Version 3.54.7. + + * remake.c (notice_finished_file): If FILE's modtime actually changed, + increment files_remade. + (remake_file): Don't increment files_remade. + + * remake.c (update_file): Don't print "up to date" messages for + phony files. + + * job.c (child_handler): Don't set C->file->update_status to 1 if + start_job returns nonzero under -n or -t. + + * expand.c (variable_expand): Count parens in $(foo:a=b) refs. + + * main.c: Removed old declaration of `glob_tilde' (which hasn't existed + for a few months). + +Tue Aug 8 23:53:43 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * job.c (exec_command): Fixed to not ignore the last path component and + to do the right thing with an empty path. + +Fri Aug 4 15:58:19 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * remake.c (library_file_mtime): Look for libLIB.a, not /libLIB.a. + Do VPATH search on libLIB.a, not /usr/lib/libLIB.a + +Thu Aug 3 20:42:00 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * job.c [HAVE_SYS_WAIT or not USG]: If WIFSIGNALED is not defined by + , define it as (WTERMSIG != 0). + +Tue Aug 1 19:25:34 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * remake.c (remake_file): If FILE has no commands and is a target, + don't set its time to now. The time gets reset by notice_finished_file + anyway, and it isn't needed since check_dep checks for nonexistence. + + * Version 3.54.6. + + * read.c (read_makefile): Don't read off the end of the string after an + `include'. + + * job.c (exec_command): New function to search the path for a file and + execute it. + (start_job): Use exec_command rather than execvp. + + * read.c (read_makefile): Expand `include' directive args before + parsing them. Allow trailing whitespace after filename. + + * variable.c (target_environment): Put makelevel + 1, rather than + makelevel, in the `MAKELEVEL' envariable. + +Sat Jul 29 10:27:04 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * remake.c (notice_finished_file): Don't get the new modtime of phony + files. + + * remake.c (remake_file): Run commands instead of touching under -t if + FILE->cmds->any_recurse is set. + + * commands.h (struct commands): Add new member `any_recurse', to be set + nonzero if any `lines_recurse' element is nonzero. + * commands.c (chop_commands): Set the `any_recurse' member. + + * commands.c (execute_file_commands): Split chopping of commands into + lines into new function chop_commands. + * commands.h: Declare chop_commands. + + * read.c (read_makefile): Test for a line beginning with a tab after + checking for conditional lines, but before all other checks. + +Fri Jul 28 18:10:29 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * read.c (read_makefile): Match directives against collapsed line + and use that for their args. + + * read.c (read_makefile): Warn about extra text after `include'. + +Tue Jul 25 14:34:25 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * make.texinfo (Rules: Directory Search: Selective Search): Fixed + example to use correct `vpath' syntax. + +Mon Jul 24 12:10:58 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * Version 3.54.5. + + * job.c (start_job): In the child side, unblock SIGCHLD. + +Fri Jul 21 18:25:59 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * make.h: Don't include #ifdef sun. + +Mon Jul 17 14:29:10 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * implicit.c (pattern_search): If ar_name (FILENAME), don't check for + directory names. + + * job.c (wait_for_children): Changed "waiting for children" message to + "waiting for unfinished jobs". + +Fri Jul 14 13:17:13 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * load.c (load_average): Use an unsigned offset into kmem. + +Thu Jul 13 18:44:49 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * variable.c (pop_variable_scope): Don't free the head of the chain of + variables in each bucket twice. + +Tue Jul 11 06:45:24 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * GNUmakefile: Include COPYING in the doc tar file. + + * variable.c, read.c, misc.c, job.c, function.c: Replace some identical + "for" loops with next_token or end_of_token calls. + +Mon Jul 10 16:55:08 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * Version 3.54.4. + + * compatMakefile: Documented new conditionals. + + * job.c: Don't define sys_siglist if HAVE_SIGLIST is defined. + Don't define dup2 if HAVE_DUP2 is defined. + + * job.c (child_handler): Interpret the return from start_job correctly. + + * remake.c (update_file_1): Don't write "target not remade because of + errors" message under -n or -q. + + * read.c: Declare getpwnam. + + * glob.c: Use if DIRENT is defined. + [USG]: Don't declare memcpy, since does. + +Fri Jul 7 20:53:13 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * misc.c (collapse_line): Copy the line over in the right place. + +Fri Jul 7 18:33:24 1989 Roland McGrath (fsf at void.ai.mit.edu) + + * remake.c: Conditionalize inclusion of on not + USG, since HP-UX defines a `struct file' there. + +Fri Jul 7 12:11:30 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * job.c: If WTERMSIG is defined by , define WAIT_T as int, + and don't define other macros; this covers HP-UX. + If WTERMSIG is not defined, use int or union wait based on USG and + HAVE_SYS_WAIT; this covers BSD and SysV. + + * Version 3.54.3 (alpha). + + * job.c [USG and not USGr3]: Include and declare errno. + + * job.c (unblock_children [USG]): Declare child_handler. + + * job.c: Renamed WRETCODE to WEXITSTATUS. + [HAVE_SYS_WAIT or not USG]: Undefine WTERMSIG, WCOREDUMP, and + WEXITSTATUS before defining them. The HP-UX defines them. + + * main.c (main): If there are no goals, fatal AFTER printing the data + base under -p. + +Thu Jul 6 22:43:33 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) + + * glob.c [USG]: #define rindex as strrchr. + + * job.c [USG]: Include and #define getdtablesize() as + NOFILE. + +Wed Jul 5 09:36:00 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * Version 3.54.2 (alpha). + + * expand.c (variable_expand): When expanding recursive variable + references (${${a}}), use the correct delimiters in the constructed + variable reference. + +Mon Jul 3 18:29:26 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) + + * compatMakefile: Clear out and redefine the .SUFFIXES list because + silly Sun 4 make defines .cps.h. + + * compatMakefile: Fix comment about -DNO_MINUS_C_MINUS_O. + + * remake.c: Include for O_* on 4.2. + + * commands.c: Define sigmask if it's not defined. + +Fri Jun 30 07:33:08 1989 Roland McGrath (roland at apple-gunkies.ai.mit.edu) + + * remake.c (remake_file): Don't always increment files_remade. + + * variable.c (push_new_variable_scope): Zero the new variable hash + table. + +Thu Jun 29 17:14:32 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * expand.c (variable_expand): When terminating the variable expansion + buffer, use variable_buffer_output instead of a simply zero store, + because the buffer may need to be enlarged. + +Wed Jun 28 16:53:47 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * Version 3.54. + + * default.c (default_suffixes): Added `.ln'. + (default_suffix_rules): Changed lint rules to use -C. + +Thu Jun 22 20:49:35 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * job.c (start_job): Set `environ' to CHILD->environment before execing + in the child process! + +Tue Jun 20 17:23:13 1989 Roland McGrath (roland at spiff.ai.mit.edu) + + * compatMakefile: Put job.h and rule.h in `srcs'. + + * Version 3.53. + +Mon Jun 19 16:25:18 1989 Roland McGrath (roland at spiff.ai.mit.edu) + + * job.c (start_job): If there are no more commands, return nonzero + under -n or -t. + + * compatMakefile (make): Pass `-f' to mv. + + * GNUmakefile: If `ARCH' or `machine' is defined, make $(ARCH)/*.o and + $(ARCH)/make instead of *.o and make. + + * function.c (string_glob): Don't try to use freed storage! + + * read.c (readline): If there is only one byte of space in the buffer, + enlarge the buffer before reading more. + + * arscan.c [M_XENIX]: Miscellaneous minor changes for Xenix. + +Sun Jun 18 13:07:45 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * GNUmakefile (depend): Split commands into two lines so they won't be + so long when variable-expanded. + + * compatMakefile: Documented MINUS_C_MINUS_O meaning. The line + describing it got removed when the USG/wait stuff was documented. + +Sat Jun 17 22:56:54 1989 Roland McGrath (roland at hobbes.ai.mit.edu) + + * Version 3.52. + +Mon Jun 12 17:45:11 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * remake.c (check_dep): Drop circular dependencies instead of fataling. + (update_file_1 already does this.) + + * default.c (default_suffix_rules): For .s -> .o, put the -o flag to + the assembler before the source file name. + +Sun Jun 11 12:00:52 1989 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * Version 3.51. + + * make.texinfo (Features): Noted 1003.2 requirement of `+' meaning. + + * file.c (remove_intermediates): If !SIG, write a single "rm" command + line, listing all files. + + * read.c (read_makefile): Don't free the storage for the passed + filename, since it might not be malloc'd. When doing an included + makefile, free the name's storage. + (read_all_makefiles): Use variable_expand to find the value of + `MAKEFILES'. Free the storage for the names of -f makefiles. + (read_makefile): Allocate storage for the makefile name in the + `struct file' in read_makefiles. + + * make.texinfo (Running: Instead of Execution): Document the effect of + + and $(MAKE)/${MAKE}. + + * make.texinfo (Functions: Foreach Function): Document that if the + iteration variable was undefined before the `foreach' call, it will be + undefined after the call. + + * commands.c: Split into commands.c, job.h, and job.c. + + * rule.c (try_implicit_rule, pattern_search): Moved to new file + implicit.c. + + * rule.c: Split into rule.h, rule.c, and default.c. + * default.c (install_default_pattern_rules): Renamed to + install_default_implicit_rules. + * make.h, main.c (main): Renamed uses. + + * make.c: Renamed to misc.c. + + * make.c (main, log_working_directory, decode_switches, + decode_env_switches, define_makeflags, die, print_version, + print_data_base): Moved to new file main.c. + + * commands.c (execute_file_commands): Don't collapse backslash-newlines + here. When chopping the commands up into lines, don't chop at + backslash-newlines. + (start_job): Collapse backslash-newlines after printing the line. + + * commands.c (start_job): Don't collapse backslash-newlines here. + (execute_file_commands): Collapse backslash-newlines before chopping + the commands up into lines. + + * commands.c (set_file_variables): Initialize the length counters for + $^ and $? to zero! + + * commands.c (start_job): Use vfork instead of fork. Someone else says + the child and parent DO have separate file descriptors. + + * variable.c: Split internals into variable.c, function expansion into + function.c, and variable expansion into expand.c. + * function.c (handle_function): New function to check for a function + invocation and expand it. + * expand.c (variable_expand): Use handle_function. + * variable.c (push_new_variable_scope): New function to push a new + empty variable set onto the current setlist. + (pop_variable_scope): New function to pop the topmost set from the + current setlist and free its storage. + * function.c (expand_function: `foreach'): Push a new variable scope + for the iteration variable and pop the scope when finished. + * variable.h: Declare new functions. + * variable.c (initialize_variable_output): New function to return a + pointer to the beginning of the output buffer. + (save_variable_output): New function to save the variable output state. + (restore_variable_output): New function to restore it. + * expand.c (variable_expand): Use initialize_variable_output. + (allocated_variable_expand): Use {save,restore}_variable_output. + * variable.c (current_setlist): Renamed to current_variable_set_list + and made global. + +Sat Jun 10 00:11:25 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * remake.c (library_file_mtime): Check for libNAME.a in the current + directory before doing VPATH search. + + * variable.c (print_variable_set): Don't write "# Variables", and write + fewer blank lines. + (print_variable_data_base): Precede the variables with "# Variables". + + * make.c (main): Print the data base under -p after doing everything + else, just before exitting. This way it gets info determined in + updating the goal targets. + + * variable.c (print_variable_data_base): Split into print_variable, + which prints one variable, and print_variable_set, which prints a set. + Replaced with a call to print_variable_set for the global set. + (print_file_variables): New function to print a given file's local + variables. + + * file.c (print_file_data_base): Call print_file_variables to print + each file's local variables. + + * commands.c (set_file_variables): Actually define the values for + the $^ and $? variables!!! + + * make.texinfo (Implicit: Pattern Rules: Automatic): Document new D and + F versions of $^ and $?. + + * commands.c (start_job): In the child fork, use getdtablesize and a + loop to close all file descriptors other than 0, 1, and 2. We need to + do this since not only the bad stdin pipe, but also some directories, + may be open. + + * commands.c (start_job): Use fork instead of vfork, because a vfork + parent and child share file descriptors, and our child needs to diddle + with stdin. + + * variable.c (initialize_file_variables): When created a new variable + set, zero out the hash table. + + * variable.c (target_environment): Don't use variables whose names are + not made up of alphanumerics and underscores. + + * remake.c (update_file_1): Set the `parent' member of each dependency + to FILE before updating it. + + * file.h (struct file): Add `parent' member. + + * variable.c (initialize_file_variables): Don't take second arg PARENT. + Use FILE->parent instead. If FILE->parent->variables is nil, recurse + to initialize it. + + * variable.h: Declare {allocated_}variable_expand_for_file. + + * variable.c (allocated_variable_expand): Now + allocated_variable_expand_for_file, calling variable_expand_for_file, + and taking second arg FILE. + (allocated_variable_expand): New function, a wrapper around + allocated_variable_expand_for_file, passing a nil second arg. + +Fri Jun 9 12:11:45 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * commands.c (start_job): On the child side of the fork, always close + the bad stdin file descriptor. + + * commands.c (struct child): New member `environment', to hold the + environment for the child. + (execute_file_commands): Set the new childs `environment' member to nil + before calling start_job. + (start_job): Set up CHILD->environment before running the commands if + it is nil. + + * make.c (main): Don't call new_environ. `shell' functions will now be + run with the environment make was called with. + + * commands.c (child_handler): Don't check C->command_ptr before calling + start_job since we now have to check C->file->cmds->command_lines and + it's easier to let start_job handle all that. + + * commands.c (struct child): New member `command_line', to hold an + index into file->cmds->command_lines. + (execute_file_commands): Set the new child's `command_line' to 0 and + its `commands' and `commands_ptr' to nil. + (start_job): When CHILD->command_ptr runs out, increment + CHILD->command_line and run the corresponding line from + CHILD->file->cmds->command_lines. Run it even under -t, -q, or -n if + the CHILD->file->cmds->lines_recurse element for that line is set. + + * commands.c (execute_file_commands): Chop CMDS up into lines, setting + its `command_lines' and `lines_recurse' members, if it wasn't already + chopped. + + * commands.h (struct commands): New members `command_lines' and + `lines_recurse'. The first is an array of chopped-up lines; the second + is an array of flags, each nonzero if the corresponding line is + recursive. + + * variable.c (variable_expand_for_file): If FILE is nil, just do a + vanilla variable_expand. + (expand_function: `shell'): Pass second arg (as nil) to + construct_command_argv. + + * commands.c (construct_command_argv): Use variable_expand_for_file on + `$(SHELL)' and `$(IFS)' instead of lookup_variable to check those + variables. This handles file-local and recursive values correctly. + To support this, take an additional argument FILE. + + * variable.c (initialize_file_variables): New function to initialize + FILE's variable set list from PARENT's setlist. PARENT is the + immediate dependent that caused FILE to be remade, or nil if FILE is a + goal. (When user-level per-file variables are implemented, PARENT + should be passed as nil when defining per-file variables.) + + * variable.c (variable_expand_for_file): New function to expand a line + using the variable set of a given file, and reporting error messages + for the file and line number of that file's commands. + + * variable.h: Don't declare lookup_variable_for_file. + + * variable.c (lookup_variable_*): Turned back into lookup_variable. It + now uses current_setlist. + (global_setlist): New static `struct variable_set_list', a setlist + containing global_variable_set. + (current_setlist): New static `struct variable_set_list *', a pointer + to the current variable set list. + (define_variable): Define in the current top-level set, not the global + set. + + * commands.c (set_file_variables): New function to set up the automatic + variables for a file in its own variable set. + (execute_file_commands): Use set_file_variables. + + * variable.c (new_environ): Replaced with target_environment, taking an + argument FILE, and returning an environment for FILE's commands. + + * variable.c, variable.h: Remove all global special variable pointers. + + * variable.c (define_variable_for_file): New function like + define_variable, but takes additional arg FILE, and defines the + variable in the variable set at the top of FILE's chain. + (lookup_variable_for_file): New function like lookup_variable, but + takes additional arg FILE, and looks the variable up in all of FILE's + variable sets. + + * file.h (struct file): New member `variables', a `struct + variable_set_list' containing the list of variable sets used in the + expansion of the file's commands. + + * variable.c (variables): Replaced with static `struct variable_set' + global_variable_set. + (define_variable): Now define_variable_in_set, taking additional + argument SET, the `struct variable_set' to define it in. + (define_variable): Use define_variable_in_set with global_variable_set. + (lookup_variable): Now lookup_variable_in_set, taking additional + argument SET, the `struct variable_set' to look it up in. + (lookup_variable): Use lookup_variable_in_set with global_variable_set. + (lookup_variable_in_setlist): New function to look up a variable in a + `struct variable_set_list' using lookup_variable_in_set. + + * variable.h (struct variable_set): New structure, containing a hash + table and the number of hash buckets. + (struct variable_set_list): New structure, containing a link for a + linked-list, and a `struct variable_set'. + + * commands.c (start_job): Under -n, return what the recursive start_job + call returns, since it might actually start a child. + + * make.texinfo (Rules: Wildcards): Document ~ and ~USER expansion. + + * commands.c (execute_file_commands): If start_job returns + failure, but -t is set, set FILE->update_status to success. + (start_job): If -t is set, and the commands are not recursive, return + failure (is is done for -q). + + * remake.c (touch_file): New function to touch FILE. + (remake_file): Use touch_file. When touching a file, still do + execute_file_commands. + + * remake.c (remake_file): Don't check question_flag (-q), since we + can't know here if the commands are recursive. + + * commands.c (start_job): Don't use the `recursive' member of + CHILD->file->cmds. Instead, check for leading +s and $(MAKE) or + ${MAKE} in the command line here. + + * commands.h (struct commands): Remove `recursive' member. + + * rule.c (install_default_pattern_rules): Remove use of `recursive' + member. + + * read.c (record_files): Don't check commands from $(MAKE) and set + their `recursive' member. + + * commands.c (fatal_error_signal): Treat SIGQUIT like SIGINT, SIGHUP, + and SIGTERM, but don't send it to ourselves because it will cause a + core dump. + +Thu Jun 8 20:30:04 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.50. + + * variable.c (variable_expand): Use allocated_variable_expand instead + of expand_argument in a few places. + + * variable.c (allocated_variable_expand): Do static variable shuffling + here instead of using expand_argument. + (expand_argument): Use allocated_variable_expand. + + * variable.c (recursively_expand): New function to recursively expand + its argument (a `struct variable'), returning the malloc'd value. + (variable_expand): Use recursively_expand. + +Sun May 28 12:49:27 1989 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * make.c (main): Fixed buggy fix in deciding to increase space for + command-line variable definitions. (First it never did it, then it + always did it; now it does it when necessary.) + +Sat May 27 14:01:54 1989 Roland McGrath (mcgrath at hecuba.Berkeley.EDU) + + * make.c (main): Fixed bug in deciding to increase space for + command-line variable definitions. + +Fri May 26 15:48:01 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * read.c (multi_glob): Use allocated_expand_variable for checking + `HOME' variable for ~ expansion, since this may be called from inside a + `wildcard' function expansion. + + * variable.h: Declare allocated_expand_variable. + + * variable.c (allocated_expand_variable): New function to do variable + expansion in an allocated buffer, rather than the static one. + + * make.c (main): Don't set glob_tilde (it no longer exists). + + * variable.c (string_glob): Use multi_glob and parse_file_seq. + + * read.c (multi_glob): Do ~ expansion here. + + * glob.c (glob_tilde, glob_filename): Removed ~ expansion. + + * variable.c (define_variable, lookup_variable): Use a smarter hashing + algorithm (the same one used for files and directories). + (VARIABLE_BUCKETS): Increased to 523. + + * file.c (enter_file, lookup_file, rename_file): Use a smarter hashing + algorithm, spreading the bits about somewhat. + + * make.c (log_working_directory): Under `-p', precede the directory + message with a `#'. + + * make.c (print_version): Under `-p', precede each line with a `#'. + (print_data_base): Precede the header line with a `#' and include the + date and time on it. + + * vpath.c (print_vpath_data_base): Precede non-directive + lines with `#'s. + + * commands.c (print_commands): Precede the non-command line with a `#'. + + * rule.c (print_rule_data_base), file.c (print_file_data_base): Precede + non-rule lines with `#'s. + + * dir.c (print_dir_data_base): Precede all lines with `#'s. + + * variable.c (print_variable_data_base): Changed format so that it can + be makefile input. Lines that are not variable definitions are + preceded with `#'. Nonrecursive variable definitions are made with all + dollar signs doubled to reproduce the initial value. Recursive + variable definitions containing newlines are done with `define' + directives. Nonrecursive variable definitions containing newlines, and + variable names containing :, =, or newlines, will come out garbled. + +Wed May 24 00:20:04 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.49. + +Tue May 23 19:18:00 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * variable.c (expand_function: `filter'/`filter-out'): Use + find_percent instead of pattern_p. + + * variable.c (expand_function: `patsubst'): Pass new args (both nil) + to patsubst_expand. + (variable_expand): For $(var:pat%=rep%) references, pass new args to + patsubst_expand so as to avoid find_percent and thus disallow + quoting the %s. + + * read.c (record_files): Pass new args to patsubst_expand. + + * variable.c (patsubst_expand): Take two new args: PATTERN_PERCENT + and REPLACE_PERCENT. Each of these, if non-nil, means that PATTERN + (or REPLACE) has already been run through find_percent, and + PATTERN_PERCENT (or REPLACE_PERCENT) is the result. + + * make.h: Declare find_percent instead of pattern_p. + + * read.c (pattern_p): Changed to find_percent, returning a pointer + to the %, or nil if there is none. + (record_files): Take another arg, PATTERN_PERCENT, a pointer to the + % in PATTERN. + (read_makefile): Pass PATTERN_PERCENT to record_files. + + * make.texinfo (Rules: Static Pattern: Static Usage, + Rules: Directory Search: Selective Search, + Functions: Text Functions): Documented that `%' can be quoted. + + * variable.c (expand_function: `filter'/`filter-out'): Use pattern_p + to allow quoted %s in patterns. + + * variable.c (patsubst_expand): Use pattern_p on PATTERN and REPLACE + to allow quoted %s. Quoting backslashes are removed from REPLACE + even if PATTERN contains no unquoted %. + + * read.c (pattern_p): Made global. + * make.h: Declare pattern_p. + + * read.c (pattern_p): New function to search for an unquoted % in a + string. Backslashes quote %s and backslashes. Quoting backslashes + are removed from the string by compacting it into itself. Returns + nonzero if an unquoted % was found, zero if not. + (record_files): Use pattern_p to check for implicit rules. + (read_makefile): Use pattern_p to check for static pattern rules. + Also use it to allow quoted %s in `vpath' patterns; warn about + `vpath' patterns with no %s. + +Mon May 22 16:31:52 1989 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * glob.c (glob_filename): Replace a `1' with the `l' that should + have been there. This incidentally stops it from dumping core. + + * glob.c (glob_filename): If the path is just a directory, with no + file name pattern, return the directory alone. + + * glob.c (glob_tilde): New global variable (int), defaults to zero. + (glob_filename): If glob_tilde is nonzero, expand ~ or ~USER. + + * variable.c (string_glob): Keep a static allocated buffer for file + names taken from the list, instead of allocating and freeing one + every time. + +Fri May 19 18:06:26 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * make.c (decode_switches): Get floating numbers from the right string. + +Sun May 14 13:48:04 1989 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * commands.c (delete_child_targets): When deleting `also_make' + files, include the target's name in the message: + make: *** [foo] Deleting file `bar' + +Sat May 13 17:34:26 1989 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * make.c (max_load_average, default_load_average): Default to -1. + + * load.c (wait_to_start_job): Return if max_load_average is < 0.0, + not equal. + +Fri May 12 16:08:05 1989 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * variable.c (variable_buffer_output): Don't try to do pointer + arithmetic between objects not in the same array. + +Wed May 10 15:55:29 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * rule.c [M_XENIX] (default_suffix_rules, default_variables): Minor + changes to allow for strange compiler syntax. + + * rule.c (default_variables): Don't include "> $@" in + $(PREPROCESS.S), since it's already in the .S.s rule. + + * file.c (enter_file): Make a new double-colon file the `prev' + member of the bottom `prev' file (the one whose `prev' is nil). + + * read.c (do_define): Append newlines after copying the lines into + the value buffer, so we end up with a trailing newline. + + * make.c (print_version): If the global variable + `remote_description' is not nil or "", append "-%s" (its value) to + the version number. + * remote-*.c: Define remote_description appropriately. + +Sun May 7 15:15:53 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * commands.c (error_status): Converted to new function child_error, + taking new arguments TARGET_NAME and IGNORED, and writing an error + message: "*** [target] Error 1" (or signal #, etc.), appending + " (ignored)" if IGNORED is nonzero. + (child_handler): Use child_error instead of error_status. + + * compatMakefile (all): Don't depend on `doc'. + + * compatMakefile (clean): Don't remove make-info*. + (realclean): New rule, depends on `clean', removes tags, TAGS, + and all Info and TeX files. + +Thu May 4 17:00:46 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * variable.c (print_variable_data_base), file.c + (print_file_data_base), rule.c (print_rule_data_base), + Use floating-point for averages and percentages. + + * make.c (print_data_base): Print messages before and after the data + base information. + + * commands.c (print_commands): Changed output format to separate + lines in commands and prefix them with tabs. + + * dir.c (print_dir_data_base): Changed output format slightly. + + * vpath.c (struct vpath, construct_vpath_list, + selective_vpath_search): Remove the `exists' member and its uses. + + * vpath.c (print_vpath_data_base): New function to print all + selective and general VPATH search paths (for -p). + + * make.c (print_data_base): Call print_vpath_data_base. + + * file.c (print_file_data_base): Changed format to look more like a + makefile rule. Now reports all information in the `struct file'. + + * rule.c (print_rule_data_base): Changed format of display from: + %: (terminal) + depends on: RCS/%,v + to: + %: RCS/%,v + is terminal. + references nonexistent subdirectory. + Also include number and percent that refer to nonexistent + subdirectories. + +Thu Apr 27 15:45:40 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * make.c (main): Figure out the level of recursion before writing + the `Entering directory' message. + * variable.c (define_automatic_variables): Don't figure out the + level of recursion from `MAKELEVEL'. It's now done in main. + + * Version 3.48. + +Wed Apr 26 16:39:17 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * commands.c (child_handler): Set `update_status' to zero when there + are no more commands. + + * make.c (log_working_directory): If MAKELEVEL > 0, indicate the + recurson in the message (make[1]: ...). + + * commands.c (child_handler): Change status to `cs_finished' when + commands fail. + + * commands.c (start_job): Return 0 (success) if there were no more + commands for the child. + (child_handler): Change the status to `cs_finished' when start_job + fails to start the commands. + + * make.c (main): Don't handle SIGEMT if it's not defined. + Do handle SIGDANGER if it is defined. + + * commands.c (child_handler): Reorganized inner loop so that it + doesn't try to inspect the child before finding it. + +Tue Apr 25 16:28:24 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * make.c (end_of_token): Fixed bug wherein backslashes caused + immediate return. + + * Version 3.47. + + * make.texinfo (Implicit: Pattern Rules: Automatic): Document + setting of `$*' for explicit rules. Add note clarifying that + automatic variables, though referred to in the documentation as + `$<', etc. are no different than `$(<)', etc. + +Fri Apr 21 18:00:12 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * file.c (enter_file): Don't strip leading `./'s. + + * read.c (parse_file_seq): Strip leading `./'s. + +Thu Apr 13 17:26:41 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * make.texinfo (Commands: Parallel, Running: Options): Document that + -l with no argument removes a previous load limit. + + * make.c (struct command_switch): New member `default_value'. + (default_job_slots): Default value (of 1) for -j. + (default_load_average): Default value (of 0, unlimited) for -l. + (command_switches): Use default values for -j and -l. + Also, -l without an arg now means no load limit. + (define_makeflags): Don't write positive_int or floating options + whose values are their defaults. + + * make.c (main): Under -w, write a `Leaving directory' message + before re-execing. + +Tue Apr 11 16:46:29 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.46. + + * Makefile: Provide an easy place for system-specific definitions + (-DUSG, etc.) and extra object files (for whatever). + + * make.texinfo: Miscellaneous fixes from RMS. + +Mon Apr 10 19:31:34 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * rule.c (pattern_search): Put rules with `subdir' flags set in + TRYRULES, since these might be valid with VPATHs. In the TRYRULES + loop, don't do lookup_file or file_exists_p calls for dependencies + of rules with `subdir' flags set, but still do vpath_search calls + and intermediate-file searches. + +Thu Apr 6 16:33:00 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * make.texinfo (Implicit: Pattern Rules: Automatic): Document the + new definition of $* for explicit rules. + + * commands.c (execute_file_commands): If FILE->stem is nil, figure + out if FILE->name ends in a suffix in the .SUFFIXES list; if so, + store the name sans suffix in FILE->stem (and $*). + +Wed Apr 5 15:24:48 1989 Roland McGrath (mcgrath at helen.Berkeley.EDU) + + * file.c (remove_intermediates): Don't use `file_exists_p' to check + for the existence of intermediate files, because the hashed + directories will probably be out of date. + + * commands.c (child_handler): Free the good stdin before running the + next command line. + + * commands.c [USG] (init_siglist): Don't case SIGEMT if it's not + defined. Do case SIGDANGER (for IBM RT) if it is defined. + + * commands.c: Changed `SYS_WAIT' to `HAVE_SYS_WAIT'. + (child_handler): Use `wait3' if HAVE_SYS_WAIT is #defined. + + * file.c (enter_file): If any `./'s are stripped off, allocate a new + copy of the shortened name. + + * rule.c (pattern_search): Allocate the right length strings for + `also_make' members. + +Sat Apr 1 13:28:38 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.45. + + * GNUmakefile: Make a separate tarfile of the DVI and info files. + + * make.c (define_makeflags): If a switch that takes an argument has + its default value, put the switch in MAKEFLAGS with no arguments. + + * make.c (command_switches): Pass `-l' in MAKEFLAGS. + +Wed Mar 29 17:50:05 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * GNUmakefile: Don't include the DVI and info files in the dist. + + * commands.c (child_handler): Don't call + check_changed_{directories,vpaths}. + + * make.h: Don't declare check_changed_{directories,vpaths}. + + * vpath.c (check_changed_vpaths): Removed this function. + + * dir.c (struct directory): Remove `modtime' member. + (find_directory): Don't set `modtime' member. + (check_changed_directories): Removed this function. + + * remake.c (update_file_1): Set FILE->command_state to cs_finished + if it didn't need to be remade. + + * remake.c (update_file): Only write the "up to date" message if the + target went from `not_started' state to `finished' state without + incrementing the count of files remade. + + * commands.c [USG] (init_siglist): If both SIGCHLD and SIGCLD are + defined, don't put them both in the `switch'. + +Tue Mar 28 15:37:02 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * file.c (rename_file): Change FILE's name!!! + + * rule.c (create_pattern_rule): Set the `terminal' member of the new + rule after calling new_pattern_rule, which zeros it. + + * rule.c (default_variables): Use $(C++) in $(COMPILE.cc)! + +Sun Mar 26 15:52:30 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Makefile: Added a `clean' target. + +Fri Mar 24 15:08:46 1989 Roland McGrath (mcgrath at helen.Berkeley.EDU) + + * Version 3.44. + + * file.c (rename_file): If a `struct file' for the renamed-to name + exists, and it is a target or has deps or commands, barf. + If not just remove the old one for put in the new one. + + * remake.c (update_file_1, check_dep): Changed it back so that equal + modtimes to NOT make dependencies be considered newer. RCS checks + out files with equal modtimes as the RCS files, so this screws it. + + * make.h, glob.c: If __GNUC__ is defined, use __builtin_alloca. + + * Makefile: Use variables `ALLOCA' and `ALLOCASRC' so systems + without a good standard alloca can get it from the Emacs + distribution (or somewhere). + + * dir.c: Don't include , since make.h does. + + * make.c: Removed debugging version of getwd. + +Thu Mar 23 16:16:27 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.43. + + * remake.c (update_file_1): If a dependency loop is found, don't + fatal. Emit an error message and remove the dependency. + + * remake.c (library_file_mtime): Fixed to use the right names. + (update_file_1, check_dep): Consider a dependency "newer" than its + dependent if they have the same modification time. + +Wed Mar 22 19:31:35 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * file.c (remove_intermediates): Don't try to remove nonexistent files. + +Mon Mar 20 10:21:22 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.42. + + * rule.c (default_variables): Set F77 to $(FC) and F77FLAGS to + $(FFLAGS) so explicit rules expecting these (which are in System V) + will work. However, there is no way to make setting these affect + the implicit rules, unless we trash FC and FFLAGS (which BSD uses). + [USG]: Set GET to `get' rather than `/usr/sccs/get'. + +Sun Mar 19 20:00:27 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * vpath.c (construct_vpath_list): Don't replace VPATH[ELEM] with + dir_name (V), because the latter may get freed. + +Sat Mar 18 15:01:39 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.41. + + * make.texinfo: Cleaned-up edition 0.1 Beta from RMS and Bob Chassell. + + * file.c (rename_file): If a file with the new name already existed, + use the same storage space, after freeing the old file's name, deps, + and `also_make' member, preserving the link in the chain. + Also write an error message telling the user to report the incident; + I don't think this should be able to happen, but I'm not sure. + + * file.c (rename_file): Don't add the hash values of the old and new + names together! Reset HASHVAL before computing the second value. + + * dir.c (check_changed_directories): Zero the new file hash table + after allocating it. + + * dir.c (dir_file_exists_p): If FILENAME is "", return 1 if the + directory exists. + + * vpath.c (check_changed_vpaths): New function to run through the + search paths of all VPATHs, making the `exists' members correspond + to reality. + + * commands.c (child_handler): Call check_changed_vpaths. + + * make.h: Declare check_changed_vpaths. + + * vpath.c (struct vpath): New element `exists', an array of char + flags; exists[N] is nonzero if searchpath[N] exists. + (construct_vpath_list): Set the `exists' member. + (selective_vpath_search): Don't search directories whose `exists' + elements are zero. + + * read.c (read_makefile): Set the `dontcare' flag of makefiles + from the MAKEFILES variable if they were not mentioned anywhere but + in the MAKEFILES variable. + + * read.c (read_makefile): Don't write an error message if fopen + fails for a makefile from the MAKEFILES variable. + + * dir.c (struct directory): Add `modtime' member to record the + modification time of the directory when it was opened. + (check_changed_directories): New function to check all known + directories; if their modtimes have changed since they were opened, + their file tables are cleared and they are reset to be read in. + + * commands.c (child_handler): Call check_changed_directories before + returning. + make.h: Declare check_changed_directories. + +Tue Mar 14 20:07:13 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.40. + + * make.c (print_version): Made the copyright say 1988, 1989. + + * read.c (read_all_makefiles): Don't set *MAKEFILES to the name of + the end of the read_makefiles chain, since the latter may be from an + included makefile. (Why did I do this before?) + + * make.c (main): Set argv[0] to "" if it was nil. Don't put the + command-line variable definitions into argv[0], only into the MAKE + variable! + +Sun Mar 5 20:44:08 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * ar.c (ar_member_date, ar_touch): Remove the trailing ) from the + member name. + +Fri Mar 3 18:15:15 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * commands.c (construct_command_argv): Initialize NEW_ARGV to 0. At + `slow' label, if NEW_ARGV is not 0, free it; then allocate 4 strings. + +Tue Feb 28 14:29:39 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.39. + + * COPYING, make.texinfo: New GNU General Public License, version 1. + + * *.c, *.h, Makefile: New copyright notices for the new GNU General + Public License, version 1. + + * commands.c [USG]: Define WRETCODE correctly (again). + + * variable.c (expand_function: `shell'): Don't capture the standard + error output of the shell command. + + * ar.c (ar_touch, ar_member_date): Allocate MEMNAME with the right + length. + + * load.c [not UMAX] (load_average): Don't clobber the first nlist + member when trying to set the second! + +Thu Feb 23 13:13:53 1989 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * commands.c (child_handler): Really ignore errors under -i and for + - lines, don't just print a different message. + + * make.c (decode_switches): Fixed handling of arguments (or lack + thereof) to switches. + +Wed Feb 22 16:25:39 1989 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * commands.c (construct_command_argv): Don't clobber LINE when + checking the IFS variable. + +Sun Feb 19 11:17:07 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * load.c [UMAX, not NO_LDAV] (load_average): Return 0.0 rather than + randomness when calls fail. + + * Version 3.38. + + * commands.c (fatal_error_signal): If handling a user kill signal + (TERM, INT, HUP), wait for the children without printing the + "Waiting for children" message, since they will die quickly. + + * Version 3.37. + + * remote-stub.c (remote_status): Take another arg, BLOCK. If this + is nonzero block waiting for remote children. If not, return 0 if + we would have to block. + + * commands.c (child_handler) [not USG]: If called as a signal + handler, use wait3 and don't block. + [USG]: If called as a signal handler, return after handling one child. + +Sat Feb 18 13:37:04 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * file.c (snap_deps): Process all double-colon entries of each file, + not just the first one. + + * Version 3.36. + + * remote-stub.c: remote.c renamed. + remote.c: Just include remote-stub.c + + * commands.c (child_handler): If we were called as a signal handler, + return after handling one child. + + * commands.c [not USG]: Include and define `sigmask' if + doesn't. + (block_children, unblock_children): Use sigmask rather than + bitshifting explicitly (and incorrectly). + + * remote.c (remote_kill): New function to send a signal to a + remote child. + + * commands.c (fatal_error_signal): If we get a SIGTERM, send one to + each living child. If we get a SIGTERM, SIGINT, or SIGHUP, delete + all pending targets before waiting for children. + (struct child): Add new member `deleted'. + (start_job): Initialize `deleted' member to 0. + (delete_child_targets): New function to delete a given child's + targets, unless the `deleted' flag in the `struct child' says they + have already been deleted. Sets this flag before returning. + +Thu Feb 16 18:32:07 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * commands.c [USG]: Define `WRETCODE' correctly (X & 0xff00). + +Tue Feb 14 16:05:00 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * commands.c (construct_command_argv): Don't make the 0th element of + the argument list be "sh" when executing /bin/sh, because start_job + uses the 0th element as the program name. + +Sun Feb 12 17:42:05 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.35. + + * read.c (readline): Put a null in the beginning of the buffer + before starting the reading loop. + + * read.c (read_makefile): Made main reading loop while + !feof (infile), and removed EOF check after calling readline. + +Sun Feb 5 19:52:38 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * remote.c (block_remote_children, unblock_remote_children): New + (stub) functions to block and restore asynchronous notification of + remote child death. + + * commands.c (block_children): Call block_remote_children. + (unblock_children): Call unblock_remote_children. + (child_handler): If called as a signal handler, block remote + children on entry and unblock them before returning. + + * commands.c (child_handler): For unknown children, if they are + remote, give their remote ID; if local, give their PID and make's. + + * commands.c (execute_file_command): Don't put a new child in the + chain unless start_job succeeds. Block children before calling + start_job, and unblock them after putting the child in the chain and + incrementing `job_slots_used' (if start_job succeeded). + + * commands.c (block_children, unblock_children): Make these globally + visible (not `static'). + commands.h: Declare block_children and unblock_children. + + * variable.c (expand_function: `shell'): Use + `shell_function_completed'. Block children before forking and + unblock after `shell_function_pid' is set properly and + `shell_function_completed' is reset to 0. + + * commands.c (child_handler): When the child of the `shell' function + completes, set `shell_function_completed' to 1 if it actually ran, + or -1 if it didn't (due to fork or exec failure). + + * commands.c (block_children, unblock_children): New functions to + block and unblock the child termination signal. + (wait_for_children): Use block_children and unblock_children. + (execute_file_commands): Block children around the critical section + wherein a new child is put on the chain. + + * make.c (main): Change the environment to contain the correct + MAKELEVEL before re-execing. + +Sat Feb 4 18:28:48 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.34. + +Fri Feb 3 16:36:49 1989 Roland McGrath (mcgrath at helen.Berkeley.EDU) + + * rule.c (default_variables): Fixed $(LINK.c). + +Wed Feb 1 18:05:07 1989 Roland McGrath (mcgrath at pepper.Berkeley.EDU) + + * Version 3.33. + + * version.c: Removed copyright notice, since this is a one-line file. + + * commands.c (error_status): Made it return BUF, rather than running + off the end (this apparently worked on Sun 3s for some reason). + + * ar.c, commands.c, dep.h, load.c, make.c, make.h, read.c, remake.c, + rule.c, variable.c, Makefile: Changed copyrght notices to cover 1989. + +Mon Jan 30 15:51:28 1989 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * Version 3.32. + +Fri Jan 27 20:09:24 1989 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * remake.c (remake_file): Don't touch phony targets. + + * rule.c (convert_to_pattern): Fixed an incorrect length passed to + savestring. + + * variable.c (expand_function: `shell'): Close the read side of the + pipe on the parent side of the fork. + + * commands.c (start_job): On the child of the fork, close the + BAD_STDIN fd if we're not using it. + + * read.c (record_files): A file beginning with a dot can be a + default target if it also contains a slash (as in `../foo'). + + * commands.c (wait_for_children): For BSD, block SIGCHLD rather than + ignoring it to avoid a race condition when child_handler is returning. + + * commands.c (child_handler): Do blocking waits. + (error_status): Return a string describing exit status. (Split out + of child_handler). + + * read.c (multi_glob): Change VECTOR to VEC for Alliant. + +Thu Jan 5 00:06:51 1989 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * Version 3.31. + + * make.texinfo (Features): Noted $(foo:PAT=SUB) from SunOS 4.0. + + * make.texinfo (Options/Recursion): -d and -p go in the environment. + + * load.c: Include "commands.h". + +Wed Jan 4 17:49:25 1989 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * make.c (switches): -d and -p can come from the environment and are + put into it. + + * read.c (record_files): Fixed the checking for duplicate deps so it + doesn't clobber the first one. + + * make.texinfo: Documented default implicit rule changes. + + * rule.c: Revamped default suffix rules. They now use Sun's style + of using variables `COMPILE.c', `LINK.c', etc. for each suffix, and + use `TARGET_ARCH' and `TARGET_MACH' variable where appropriate. + Also support Modula-2 compilation (suffixes .sym, .def, and .mod). + Ratfor Yacc support is gone, since nobody has yacc -r. + All EFL support is gone, since nobody uses EFL. + + * ar.c, arscan.c: Don't assume `long int' and `int' are the same. + + * commands.c [USG]: Fixed wait status bit encoding. + [USG and not USGr3] (dup2): Define this for SysVr2. + + * make.h, dep.h, make.c [iAPX286]: Make allowances for this + brain-damaged compiler. + + * make.texinfo (Variables: Flavors): Fixed a typo. + +Tue Jan 3 18:09:31 1989 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * ar.c (ar_member_date, ar_touch): Truncate member names to 15 chars. + + * Version 3.30. + + * commands.c [SYS_WAIT]: If this is defined, use BSD + and wait3 even if USG. + + * read.c (record_files): Defining .DEFAULT with no deps or commands + clears its commands. + + * rule.c (default_suffixes): Added `.sh'. + (default_suffix_rules): Added single-suffix .sh rule, copies source + to target and makes target executable. + make.texinfo (Catalogue of Rules): Documented .sh rule and its use + in conjunction with SCCS. + + * rule.c (set_default_suffixes): Define variable `SUFFIXES' to the + default list ("" under -r). + make.texinfo (Suffix Rules): Document `SUFFIXES' variable. + + * rule.c (default_variables), make.texinfo (Implicit Variables): + Variable AR defaults to `ar', ARFLAGS to `rv', and RM to `rm -f'. + + * rule.c (install_default_pattern_rules): Default variables are made + recursive. + (default_variables): Added "CPP", defined to "$(CC) -E". + (default_suffixes): Added `.S', before `.s'. + (default_suffix_rules): New rule for .S to .s, runs CPP. + All rules that use CPP now include "$(CPPFLAGS)". + make.texinfo (Catalogue of Implicit Rules, Implicit Variables): + Documented above changes. + + * commands.c [USG] (sys_siglist): Don't define. + [USG] (init_siglist): New function to initialize sys_siglist. + + * make.texinfo (Variables: Reference): Documented `$(foo:PAT=SUB)' + references. + + * variable.c (variable_expand): A reference `$(foo:PAT=SUB)' is + equivalent to `$(patsubst PAT,SUB,$(foo))'. + + * variable.c (variable_expand): Free the storage for the expansion + of a recursive variable when it is nod longer needed. + + * variable.c (variable_expand): When checking for `$($(foo))', use + lindex so as not to search for the second `$' outside the parens. + + * make.c (struct stringlist, main, decode_switches): Changed `index' + member to `idx'. + +Sat Dec 24 16:02:32 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * commands.c (wait_for_children [USG]): Handle SIGCLD with SIG_DFL, + rather than SIG_IGN. Ignoring SIGCLD reportedly makes wait return -1. + + * arscan.c [USGr3]: Define PORTAR to 1 (as with sun386). + (ar_scan [USGr3]): Remove trailing slashes from member names. + +Thu Dec 22 17:54:05 1988 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * make.texinfo (Makefiles: Overriding Makefiles): New node + documenting use of .DEFAULT to have one makefile defer unmakeable + targets to another. + + * make.texinfo (Implicit: Using Implicit, Implicit: Last Resort): + Mention empty commands and xref node `Empty Commands'. + +Wed Dec 21 20:12:40 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * Version 3.29. + + * make.c (struct command_switch, command_switches, et al): New + member `noarg_value', if not nil, ptr to value to use if no arg is + given to a switch that would otherwise require one. The -j option + can now be given w/o an arg, to mean infinite jobs. + * commands.c: If job_slots is zero, infinite jobs. + + * read.c (read_all_makefiles, read_makefile): Make makefiles precious. + + * make.c (decode_switches): For a positive_int or floating option, + if we moved to the next argument word, but found no argument for the + option, move back to the correct word. + + * make.c (decode_switches): If we got any unknown options, die after + processing all arguments. + + * GNUmakefile: Moved `include depend' to the end, so the default + goal will be set before then. + + * load.c (wait_to_start_job [Unix, UMAX]): Merged into one version + under #ifdef LDAV_BASED. Only loop while we have jobs running. + Sleep for increasing amounts (increase one second per iteration) + before checking the load average (after the first check). + Get the load average from function load_average. + (wait_to_start_job [not LDAV_BASED]): Always return. + (load_average [UMAX]): Fetch load average for Encore UMAX. + (load_average [not NO_LDAV]): Fetch load average from /dev/kmem. + [not NO_LDAV]: Define LDAV_BASED. + +Tue Dec 20 18:54:50 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * Version 3.28. + + * commands.c (wait_for_children): Take second arg, ERROR. If + nonzero, and there are children, print a message on stderr. + (execute_file_commands, fatal_error_signal): Pass second arg. + * make.c (die), remake.c (update_goal_chain), variable.c + (expand_function: `shell'): Ditto. + +Sat Dec 17 01:05:38 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * commands.c (start_job): Call wait_to_start_job before forking. + + * load.c (load_average): Converted to wait_to_start_job. + + * remote.c: New file for remote execution functions. + (start_remote_job_p): Return nonzero if the next job should be run + remotely. + (start_remote_job): Start a remote job and return an ID for it. + (remote_status): Get status of dead remote children. + +Fri Dec 16 16:51:07 1988 Roland McGrath (mcgrath at hecuba.Berkeley.EDU) + + * commands.c (start_job): If start_remote_job_p () returns nonzero, + call start_remote_job to start the job rather than fork and exec. + (child_handler): + + * commands.c (execute_file_commands): Moved load average checking to + start_job. + + * commands.c (child_handler: USG): Record the pid wait returns. + + * load.c (UMAX): Added some #include's needed for UMAX. + + * read.c (multi_glob), variable.c (string_glob): Ignore a (char **) + -1 return from glob_filename. + + * variable.c (variable_expand): Make sure we don't increment past + the end of the string we were passed. + + * variable.c (variable_expand): Terminate the expansion. + + * file.c (rename_file): If there is already a file under the new + name, set its contents equal to FILE's (ick). + + * variable.c (define_automatic_variables): Pass all the args to + define_variable when defining MAKELEVEL! + + * commands.c (execute_file_commands): If max_load_average > 0, and + we have children running, don't start up another child until the + load average goes below max_load_average. + + * make.c: New variable `max_load_average'. + (struct command_switch, decode_switches, decode_env_switches): + Handle floating-point (double) args. + (command_switches): Added `-l' switch to set `max_load_average'. + + * load.c (load_average): New file and function to return a double + that is the current load average (1.00 scale). + * GNUmakefile, oldMakefile: Pass flags in $(LOAD_AVG) for load.c. + +Thu Dec 15 15:22:08 1988 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * Makefile: Renamed to oldMakefile. + * GNUmakefile: Make Makefile from oldMakefile and depend. + + * read.c (read_all_makefiles): When putting the default makefiles in + the read_makefiles chain so they will be remade, put them in the + right order. + + * remake.c (update_goal_chain): If MAKEFILES is nonzero, always make + in serial, and return as soon as one goal whose `changed' member is + nonzero is successfully remade. + + * commands.c: Don't include . + + * commands.c (construct_command_argv): Added ` to sh_chars. + + * make.h: Don't declare construct_makeflags. + + * make.c (main): Set up MAKEFLAGS and MFLAGS and make an environment + both before and after reading the makefiles, so the makefiles can + use them and possible change them, and later children will get the + right information. + (construct_makeflags): Replaced with define_makeflags (static void), + which defines the two variables. + * variable.c (define_automatic_variables): Don't define MAKEFLAGS + and MFLAGS. + +Mon Dec 12 14:40:31 1988 Roland McGrath (mcgrath at helen.Berkeley.EDU) + + * Version 3.27. + + * commands.c (child_handler): Reset the handler to ourselves when + called for USG, since it has no safe signals. + + * commands.c: For USG, use an int rather than a `union wait' for + wait calls, and dissect it with bitmasks. + (child_handler): No wait3 system call in USG. Since we can't + protect from hanging, always return immediately if we have no + children we know about and we're not running a `shell' function. + (There is still the danger of hanging waiting for a child that died + without our being notified.) + + * remake.c: Include instead of . What we need + is really in , and while BSD includes + , USG doesn't. + + * make.c (main): Figure out the program name before doing anything + which might need it (in a call to error or fatal). + + * dir.c, glob.c: Use `struct dirent' and for USGr3. + + * arscan.c (ar_scan): Added missing & before buf (which is an int) + if SARMAG is not defined (SysV). + +Fri Dec 9 18:44:13 1988 Roland McGrath (mcgrath at pepper.Berkeley.EDU) + + * Version 3.26. + + * dir.c (find_directory, dir_file_exists_p): Keep track of how many + directories we have open and don't let it be more than + MAX_OPEN_DIRECTORIES (currently 10). + + * variable.c (expand_function: `foreach'): Use expand_argument + rather than variable_expand so each repetition doesn't clobber the + last!!! + +Mon Dec 5 15:58:46 1988 Roland McGrath (mcgrath at hecuba.Berkeley.EDU) + + * Version 3.25. + + * Makefile: Define `install' target. + + * GNUmakefile: Don't include GNUmakefile or depend in the + distribution file. + +Wed Nov 30 15:53:42 1988 Roland McGrath (mcgrath at helen.Berkeley.EDU) + + * commands.c (execute_file_commands): Don't clobber a null into + random storage if there were no $^ and/or $? words. + + * remake.c (check_dep): Set *MUST_MAKE_PTR nonzero if a dependency + doesn't exist. + + * ar.c (ar_member_date, ar_touch): Make sure the modtime of the + archive file itself is known before we fetch or change the modtime + of one of its members. + + * read.c (read_makefile): Expand variable and function references + before parsing rules so variable can contain special characters + (colons and semicolons). + +Sat Nov 26 11:36:31 1988 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * variable.c (expand_function: `filter', `filter-out'): Fixed so + that filter-out works right. + + * variable.c (expand_function: `filter', `filter-out'): Made these + functions use each word of their first argument as a pattern. + +Fri Nov 25 10:51:47 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.24. + + * read.c (record_files): If a target is listed more than once in a + single rule (that defines commands), give a warning message rather + than the counter-intuitive message saying commands were already + defined (in the same place). + + * make.c (fatal, error): Made them both take 6 args since there is + at least one error message that need that many. Too bad vfprintf is + not universal! + + * Version 3.23. + + * read.c (read_makefile): Moved the construction of the `struct + commands' into record_files. Call record_files before recursing for an + included makefile so the higher-up will determine the default goal. + (record_files): Take arguments COMMANDS, COMMANDS_IDX and + COMMANDS_STARTED and construct a `struct commands. + +Thu Nov 24 14:36:33 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.22. + + * make.c (main): Made it a fatal error if we can't move back to the + directory we started in before re-execing. + + * make.c (main): Get the current directory before doing anything + else, so we know it even if we don't need it for the value of + `MAKE', since we might want it when re-execing. + +Wed Nov 23 13:34:44 1988 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * Version 3.21. + + * read.c (record_files): Eliminate duplicate deps in a chain. + + * variable.c (expand_function: `sort'): Pass the right number to + qsort, not one less. + + * remake.c (remake_file): Always call notice_finished_file if + FILE->command_state == cs_finished. + + * commands.c (execute_file_commands): Call notice_finished_file to + set FILE's status correctly when start_job fails (because it's out + of commands or running under -n). + +Fri Nov 18 15:31:12 1988 Roland McGrath (mcgrath at saffron.Berkeley.EDU) + + * Version 3.20. + + * remake.c (update_file_1): Set the `update_status' of FILE to + nonzero and set FILE's `updated' bit if we have decided to give up + on remaking FILE because of errors in the dependencies. + + * rule.c (pattern_search): Debugging messages use `dependency' (vs. + `dependent') properly. + + * make.texinfo (Conditionals: Conditional Syntax): Function index + entries for `ifndef' and `ifneq'. + + * variable.c (define_automatic_variables): Define `MAKELEVEL' to the + decimal number of the makelevel, since it may be malformed or blank. + + * remake.c (remake_file): Call notice_finished_file after touching. + +Sat Nov 12 19:29:34 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * Version 3.19. + + * GNUmakefile (dist): Pass the `-f' flag to compress. + + * vpath.c (build_vpath_lists): Check for VPATHS being nil after + constructing the general VPATH list from the `VPATH' variable. + +Fri Nov 11 08:02:26 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * make.c (fatal, error): Made error messages for recursive runs be + shorter. + +Thu Nov 10 16:51:36 1988 Roland McGrath (mcgrath at basil.Berkeley.EDU) + + * Version 3.18. + + * read.c (read_makefile): Made it eat leading spaces and formfeeds + (but not tabs), like it's documented to. + + * read.c (read_makefile): Let included makefiles determine the + default goal, as is done by System V Make. + +Tue Nov 1 19:03:08 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * variable.c (new_environ): Don't increment VCNT when a variable is + rejected. + +Fri Oct 28 16:54:15 1988 Roland McGrath (mcgrath at basil.Berkeley.EDU) + + * Version 3.17. + + * rule.c (convert_to_pattern): Don't use the same storage for a name + in two rules since new_pattern_rule may free this storage when a + rule is discarded. + + * rule.c (new_pattern_rule): Undid useless change I made Oct 25. + +Thu Oct 27 19:17:53 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * Version 3.16. + + * GNUmakefile, Makefile: Fixed a typo in a comment. + * Makefile: Removed malloc.o from object file list. + + * variable.c: Removed old debugging #define's for xmalloc and + xrealloc so non-ANSI cpp's won't barf. + + * make.c (main): Made local array for temp file name static so + compilers that don't do auto aggregate initialization won't barf. + + * read.c: Removed static declaration of copy_dep_chain since it is + no longer static. + +Tue Oct 25 16:59:30 1988 Roland McGrath (mcgrath at pepper.Berkeley.EDU) + + * rule.c (new_pattern_rule): If we threw out the new rule because it + matched an old one and OVERRIDE was zero, don't put the freed + pointer in the chain! + +Wed Oct 19 15:07:43 1988 Roland McGrath (mcgrath at pepper.Berkeley.EDU) + + * Version 3.15. + + * variable.c (expand_function: `sort'): Don't do the sorting and + writing out if there were no words in the first place. + + * remake.c (remake_file): Only fail with a "no way to make" message + for a dependency (non-target) file. If we don't know how to remake + a target file, pretend it was successfully remade and is very new. + + * remake.c (remake_file): Don't increment `files_remade' for a + non-target file we don't know how to remake. + + * read.c (record_files): Don't die with "both : and :: entries" for + a file whose `is_target' flag is not set. + +Tue Oct 18 17:24:11 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * variable.c (expand_function: `patsubst', `subst'): Free the right + things! + + * variable.c (expand_function: `subst'): Don't clobber the + pointer to the end of the second arg and then try to use it!!! + +Mon Oct 17 16:44:45 1988 Roland McGrath (mcgrath at catnip.Berkeley.EDU) + + * variable.c (expand_function: `patsubst'): Don't clobber the + pointer to the end of the second arg and then try to use it!!! + + * variable.c (expand_function: `word' function): Made it parse its + second argument correctly. + + * ar.c (ar_touch): Return 1 rather than -1 for on errors. + +Sat Oct 15 15:12:16 1988 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * Version 3.14. + + * GNUmakefile: Removed explicit rule for make.dvi since the built-in + implicit rule now works. + + * rule.c (default_suffix_rules): Fixed .texinfo.dvi rule yet again + so that it really works, now that parens are counted. + + * remake.c (update_file_1): Set FILE's `updated' flag after calling + remake_file if it failed or finished immediately. + + * remake.c (update_file): Use the `updated' flag rather than the + command state to decide if a file was fully considered, and + therefore might give an "up to date" message. + + * variable.c (expand_function): Made all functions that take more + than one argument count parens of the appropriate flavor in their + args and ignore commands nested in parens. + +Fri Oct 14 18:35:00 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * read.c (read_all_makefiles): Pass second arg to read_makefile for + default makefiles. + +Thu Oct 13 16:40:08 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * Version 3.13. + + * GNUmakefile: Added an explicit rule for make.dvi since the + built-in .texinfo.dvi implicit rule is screwed up. + + * rule.c (default_suffix_rules): Added a comment that the + .texinfo.dvi rule does not work because of an ahem, feature of Make + that at some point will be fixed--er, enhanced to alleviate this + difficulty. + + * rule.c (default_suffix_rules): Fixed Texinfo -> DVI rule (again). + + * make.texinfo (Commands: Execution): Documented new competing for + standard input among children. + + * commands.c (struct child): Added `good_stdin' flag to tell if this + child has the stdin that doesn't point into nirvana. + (good_stdin_used): New variable to tell if any child has the good + standard input. + (child_handler): Reset `good_stdin_used' if a dead child's + `good_stdin' flag is set. + (start_job): Give the new child the good standard input if + `good_stdin_used' is no set, and set the child's `good_stdin' flag + appropriately. + + * rule.c (default_suffix_rules): Changed Texinfo -> DVI rule to work + better (I hope). + + * read.c (read_all_makefiles): Stop reading default makefiles after + one is found. + + * read.c (read_makefile): Reset `reading_filename' and + `reading_lineno_ptr' after recursing for an included makefile. + + * GNUmakefile: New GNU Make-specific makefile that does everything + Makefile does plus distribution stuff, and doesn't contain any hacks + to try to work with Unix make. + + * Makefile: Removed distribution stuff. + + * make.c (main): Use mktemp to construct the names of temporary + files used for standard input makefiles. + + * make.c (main): Don't turn standard input into a broken pipe. + + * commands.c (start_job): Keep two extra file descriptors around: a + good standard input, and a bad one that reads from a broken pipe. + On the child side of the fork, if there are other children, give + this one the broken pipe so they won't compete; if this is the only + one, give it the good standard input. + + * make.h: Declare notice_finished_file. + + * commands.c (execute_file_commands): Use noticed_finished_file + after waiting for the child when there is only one job slot. + + * remake.c (notice_finished_file): New function to re-check mtime's + and such things to be done when commands finish. + (update_file_1): Use notice_finished_file. + + * commands.c (child_handler, execute_file_commands): Use new + variable `job_slots_used' to record the number of jobs currently + running, rather than diddling with `job_slots'. + (execute_file_commands): Increment `job_slots_used' before calling + start_job and decrement it on failure to avoid race condition. + If there is only one job slot, wait for the child to finish and + return its status so commands are run in linear order, as if there + were no parallelism. + +Wed Oct 12 15:59:03 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * remake.c (remake_file): Don't print a "No way to make" message for + targets whose `dontcare' flags are set. + + * read.c (read_all_makefiles): Set the `dontcare' flag of the + `struct file' each default makefile added to the chain. + + * file.h (struct file): Add `dontcare' member. + + * read.c (read_all_makefiles): When no default makefiles are found, + put the names of all those tried in the `read_makefiles' chain so + they will be updated if possible, giving their `struct dep's' + `changed' members the value of 0 so we won't care if they cannot be + found or remade. + + * make.texinfo (Makefiles: Remaking Makefiles): Documented that + default makefiles will be remade if not found. + + * read.c (read_all_makefiles): If no default makefiles can be found, + go through the list of default names, trying to make one, stopping + if one is made. + + * remake.c (remake_file): Set STATUS to 0 after successfully touching. + + * dir.c (file_impossible, file_impossible_p): Don't clobber FILENAME + to "" and then try to to a strcmp on it!!! + +Mon Oct 10 16:09:18 1988 Roland McGrath (mcgrath at cinnamon.Berkeley.EDU) + + * make.c (main): Don't do `dir_load (".")'. + + * rule.c (count_implicit_rule_limits), vpath.c + (construct_vpath_list): Test the existence of a given directory by + `dir_file_exists_p (DIR, ".")' and assume that if this returns zero, + it means the directory really does not exist. + + * dir.c (struct dirdata): Replaced with `struct directory' for + directories, each containing a chain of `struct dirfiles', one for + each file (real or impossible). + (dir_load): Removed. + (find_directory): New function to find the `struct directory' for a + named directory and return it (possibly creating a new one). + (dir_file_exists_p): Read the directory on the fly if its stream is + still valid (and ever was) if the file we're looking for is not + already in the hash tables. + (file_impossible, file_impossible_p, dir_name, print_dir_data_base): + Use the new directory/file scheme. + + * make.texinfo: Miscellaneous editorial changes and clarifiactions. + + * commands.c (struct child): Remove `environ' member. + (child_handler, start_job, execute_file_commands): Remove use of + `environ' member and new_environ. + + * make.c (main): Call new_environ after reading makefiles. + + * variable.h: Declare `new_environ' to return void. + + * variable.c (new_environ): Put the environment in `environ' and + return void. + +Fri Oct 7 15:48:39 1988 Roland McGrath (mcgrath at pepper.Berkeley.EDU) + + * Version 3.12. + + * Makefile: Don't make the uncompressed tar file. + + * variable.c (expand_function: `shell' function): Made it not expect + read to null-terminate the buffer. + + * Makefile: Made it use a temporary symlink to . rather than a + temporary directory to make the distribution tar file. + +Thu Oct 6 17:52:35 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.11. + + * make.texinfo: Fixed a line that got garbaged somehow. + +Mon Oct 3 16:14:39 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * make.c (main): Try to move back to the directory we started in + before re-exec ourself. + + * remake.c (update_file_1): A double-colon target with no deps + always needs to be remade. + + * remake.c (remake_file): Changed "No way to make" message to say + `target' rather than `file'. + +Sun Oct 2 12:50:47 1988 Roland McGrath (mcgrath at catnip.Berkeley.EDU) + + * remake.c (update_file_1): Set FILE->update_status to the return + value of remake_file. + + * rule.c (convert_to_pattern): Fixed swapped lengths passed to + xmalloc for source/target suffixes. + + * make.texinfo: Documented that MAKEFLAGS and MFLAGS are read in + from makefiles. Updated the `Features' section a bit. + + * make.c (main): Read switches from MAKEFLAGS and MFLAGS variables + after reading in makefiles. + + * make.c (main): Put a line "/tmp/foo:;" rather than ".PHONY: + /tmp/foo" in front of temp files made for stdin makefiles. + + * remake.c (update_file): Test the state of the right `struct file' + for double-colon files. + + * make.c (main): Put a ".PHONY: /tmp/foo" line in front of temp + files made for stdin makefiles so they won't be remade when we + re-exec. Kludge-o-matic!! + + * remake.c (update_goal_chain): Judge files as being finished based + on their `updated' flag, not their state. + + * read.c (read_makefile): Don't check for FILENAME being "-". + (read_all_makefiles): Set each element of MAKEFILES to the name put + in READ_MAKEFILES by read_makefile, since read_makefile may free the + storage for the name it is passed, and someone might want to look at + the elements of MAKEFILES again. + + * make.c (main): For each `-f' flag with arg `-' (standard input), + read standard input into a temp file and pass the temp file's name + to read_all_makefiles, after making sure it will not be remade. + + * make.c (construct_makeflags): Always put out `-j1'. + +Sat Oct 1 00:19:59 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * commands.c (execute_file_commands): If commands are nothing but + whitespace, set the state to `cs_finished' before returning 0. + + * make.c (decode_switches): Allocate space for args in stringlists + so they can be freed later. + + * make.h: Declare `makelevel'. + + * variable.c (makelevel): Moved to make.c (and made global). + + * make.c (fatal, error): Print the makelevel if it's > 0. + (perror_with_name): Use error rather than calling fprintf directly. + (pfatal_with_name): Use fatal rather than fprintf and die. + + * variable.c (new_environ): Don't put default variables (origin + `o_default') into the environment; they just take up space. + + * read.c (read_makefile): Don't add FILENAME to the chain of read + makefiles if it's "-" (standard input). + + * remake.c (update_goal_chain): Set STATUS correctly when nothing + happens (as well as in all other situations). + + * make.c (construct_makeflags): Put a `-' before each switch and + spaces between them. + + * Version 3.10. + + * commands.c (wait_for_children): Don't check if `children' is nil. + This is the case when waiting for the child of a `shell' function. + + * dir.c (dir_load): Don't add a hash-table entry for directory + DIRNAME and filename "" if DIRNAME doesn't exist. + + * commands.c (execute_file_commands): Return 0 after start_job + returns 1 (failure) under the -n flag. + + * remake.c (remake_file): Set the state to `cs_finished' when not + calling execute_file_commands. + + * remake.c (update_goal_chain): Second arg is now MAKEFILES, nonzero + meaning to disable -t, -q, and -n for each target unless the target + was also given on the command-line. + + * read.c (read_makefile): Enter the `struct file's for the makefiles + added to the `read_makefiles' `struct dep' chain. + + * remake.c (update_goal_chain): Made it not enter the files for the + goals in the chain. It will already have been done. + + * rule.c (convert_to_pattern): Null-terminate the names of targets + and deps of the pattern rules properly. + +Fri Sep 30 18:56:20 1988 Roland McGrath (mcgrath at nutmeg.Berkeley.EDU) + + * make.c (main): Call install_default_pattern_rules. + + * make.h: Declare copy_dep_chain. + + * read.c (copy_dep_chain): Moved to make.c (and made global). + + * make.c (main): Call update_goal_chain to update goals. + Update read makefiles and re-exec self if they change. + + * remake.c (update_file): Make this function static. + (update_goal_chain): New function to update a `struct dep' chain of + goals, waiting until they are all finished before returning. + + * make.h: Don't declare update_file. Declare update_goal_chain. + + * make.c (main): Call snap_deps, etc. that were in read_all_makefiles. + + * read.c (find_makefile): Removed this function. + (read_all_makefiles): Don't update makefiles, don't diddle with + pattern rules, don't call snap_deps, etc. Return a `struct dep' + chain of all makefiles read. + (read_makefile): Now takes two args: FILENAME and TYPE, which is 0 + for a normal makefile, 1 for MAKEFILES variable or 2 for an included + makefile. Add a `struct dep' containing the name of the makefile + (as it was found in the search path for type 2s), and TYPE in the + `changed' member to the global `read_makefiles' chain. + + * make.h, rule.c (displace_pattern_rules, + add_displaced_pattern_rules): Removed these functions. + + * read.c (read_makefile): Variable-expand the name of an `include'd + makefile before calling find_makefile on it. + + * file.c (snap_deps): If the `struct file' for a `struct dep' + already exists, free the `struct dep's `name' member before setting + it to nil (since this info is in the `struct file'). + + * read.c (copy_dep_chain): Made it copy each name rather than + leaving multiple `struct dep's with the same pointers. + +Thu Sep 29 19:08:13 1988 Roland McGrath (mcgrath at catnip.Berkeley.EDU) + + * make.c (decode_switches): Fixed second decode_env_switches call to + use correct length of "MFLAGS" (6, not 5). + + * read.c (read_makefile): Don't stop reading when readline returns + zero lines read. Only stop when the stream reaches EOF. This makes + it recognize the last line of a makefile without a newline. + + * remake.c (remake_file): If we don't know how to make FILE, set its + command state to `cs_finished'. + + * remake.c (update_file): Don't write the "up to date" message if + update_file_1 returned a nonzero status. + +Wed Sep 28 16:30:07 1988 Roland McGrath (mcgrath at catnip.Berkeley.EDU) + + * commands.c (child_handler): Set the `update_status' member + properly for ignored errors. + + * rule.c (convert_to_pattern): Made it not care about if the target + suffix comes before the source suffix in the .SUFFIXES list. + + * make.texinfo: Misc editorial changes. + + * commands.c (wait_for_children): Return immediately if `children' + is nil (there are no children). + +Tue Sep 27 15:33:14 1988 Roland McGrath (mcgrath at pepper.Berkeley.EDU) + + * Version 3.09. + + * commands.c (struct child): New member `command_ptr' to hold the + current position in the commands. The `commands' member is never + changed. + (start_job, child_handler, execute_file_commands): Use new method + for `commands' and `command_ptr' members. + + * make.c (decode_env_switches): Skip past an invalid letter (instead + of looping forever). + + * commands.c (struct child): Add `environ' member to hold the + environment for this child. + (execute_file_commands): Get a new environment from new_environ and + put in the the new `struct child's `environ' member. + (child_handler): When freeing a child, free its `commands' member, the + elements of its `environ' array and its `environ' member itself. + (start_job): Set `environ' to the child's `environ' member before + exec'ing the command. + + * variable.h, variable.c (new_environ): Made it return the new + environment, not putting it in `environ'. + + * remake.c (update_file): Don't give a "is up to date" message + unless no files were remade and the state went from `cs_not_started' + to `cs_finished', so repeat calls to finish jobs won't get the message. + +Mon Sep 26 16:26:08 1988 Roland McGrath (mcgrath at helen.Berkeley.EDU) + + * Version 3.08. + + * make.texinfo (Commands: Execution): Documented that children will + be waited for rather than killed. + + * commands.c (fatal_error_signal): Wait for children. + (kill_children): Removed this function. + + * make.c (main, die): Wait for children to die, don't kill them. + + * variable.c (expand_function): Use wait_for_children. + + * make.c (main): Use wait_for_children rather than child_handler. + + * commands.c (wait_for_children): New function to block waiting for + children, insuring that child_handler is not called recursively. + (execute_file_commands, kill_children): Use wait_for_children. + + * commands.c (child_handler): Start up additional commands in a + sequence after an ignored error. + + * remake.c (update_file): Don't print "`foo' is up to date" messages + when update_file_1 returns while commands are executing. + + * remake.c (update_file_1): Pass the file name to name_mtime, not + the bloody `struct file', dammit!! + + * commands.c (child_handler): Print out the "*** ..." error message + when not under -i. (I somehow forgot this.) + + * remake.c (update_file_1): Use name_mtime rather than file_mtime to + re-get the mtime of a file whose commands have finished. + + * make.c (command_switches, decode_switches, decode_env_switches): + Make all switches that take string args allow them right after the + switch letter. + + * commands.c (child_handler): Check for a child being the `shell' + function's command returning and set the global variable for + expand_function to check. + + * variable.c (expand_function): For the `shell' function, instead of + waiting for the child shell ourselves, let child_handler do it and + loop around waiting for something to happen. + + * make.c (print_version): Made the copyright year static, not dynamic. + + * make.h, make.c: Remove construct_argv function. + + * make.c (main): Say "no goal target" instead of "no target". + + * make.texinfo (Commands: Parallel): Don't send SIGKILL. + + * commands.c (kill_children): Don't send SIGKILL to children that + aren't killed by the first signal. + + * make.c (main), commands.c (kill_children): Decide between SIGCHLD + and SIGCLD based on whether or not SIGCHLD is defined, not on USG. + + * Makefile: Link make with $(LOADLIBES). + + * read.c (construct_include_path): Fixed another bad xrealloc call. + + * make.c (decode_switches): Fixed an xrealloc call with no first arg. + +Sat Sep 24 01:16:21 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * Version 3.07. + + * remake.c (update_file_1): If deps are running, set state to + `cs_deps_running' and return 0. If deps are done, run commands. + + * commands.c (child_handler): Made it delete non-precious targets + killed by fatal signals. + + * make.texinfo: Documented parallelism. + +Fri Sep 23 16:52:27 1988 Roland McGrath (mcgrath at helen.Berkeley.EDU) + + * remake.c (update_file_1): Don't return if FILE's state is + `cs_deps_running'. In that case, we need to run through and check + the states of all our dependencies. + + * commands.c (execute_file_commands): Decrement `job_slots' after + starting a new job to run file commands. + + * commands.c (start_job): Made it set the state to `cs_running'. + + * make.c (main): Fixed usage of `g', `lastgoal', and `goals' in the + goal-making loop. + + * commands.c (child_handler): When commands finish, set the + corresponding file's `update_status' and `updated' flags as + appropriate, and reset the modtimes of the file and any `also_make' + files it has. + + * remake.c (remake_file): Don't re-set `last_mtime' and set `updated'. + + * commands.c (fatal_error_signal): Don't swallow all the children + with a loop around `wait ((union wait *) 0)'!!! + + * make.c (struct command_switch): Added `positive_int' type. + (switches): Added -j (job_slots). + (construct_makeflags, decode_switches, decode_env_switches): + Handle`positive_int'-type switches. + + * glob.c (glob_vector): Rename local variable `vector' to `VeCtOr'. + This is said to avoid a conflict with some system's global `vector' + variable. + + * variable.c (expand_function): Made the `shell' function use + construct_command_argv and do its own child control and piping. + + * make.c (main): Turn standard input into a broken pipe after + reading in all makefiles (the last time it will be needed). + + * commands.c (struct child): Remove `pipe_fd' member. We don't use + pipes any more. + (start_job): Return 0 for success, 1 or failure (rather than void). + Don't use pipes. Don't turn the child's stdin into a broken pipe. + (child_handler): Print "*** Error" messages when necessary. + Die on failed commands when -k was not given. + (execute_file_commands): Check the return of start_job and remove + the child from the chain and return failure if it is nonzero. + + * make.c (die): New function to clean up and exit. + (fatal, pfatal_with_name): Use die. + +Thu Sep 22 14:27:11 1988 Roland McGrath (mcgrath at helen.Berkeley.EDU) + + * commands.c (struct child): Added `commands', `pipe_fd', and + `noerror' members to keep track of info about a command thread. + (start_job): New function to start a job and update the argument + `struct child' to reflect its status. + (execute_file_commands): Merged run_file_commands back in. + Made it use new start_job function. + + * rule.c (freerule): Don't free the `struct commands' of the + discarded rule. It may be used in more than one place. + + * commands.c (execute_command_line): Made it not try to delete the + possibly partly-made file. The child_handler function will do this. + (fatal_error_signal): Ditto + call kill_children. + + * make.h: Declare job_slots. + + * make.c (main): Collect goals in a dep chain and run through this + chain waiting for a child, eliminating finished goals, updating all + remaining goals, and quitting if they fail and not -k. + + * commands.c (child_handler): If called with SIG < 0, - SIG is the + max number of children to bury. + + * commands.c (child_handler): If called with SIG as zero, + block waiting for running children. + (kill_children): Call child_handler with zero rather than SIGCHLD. + + * remake.c (update_file_1): Use the `command_state' member of FILE + and its dependencies to determine what commands are running, what to + do, etc. If commands or dep commands are running when we are + called, return success (0). If commands finished since the last + time we were called, return their status. + + * commands.h: Declare kill_children. + + * commands.c: Define `struct child' to keep track of child + processes, with the chain in `children'. + (child_handler): New function to catch child-termination signals + (SIGCHLD, or SIGCLD for USG), store the returned status in the + appropriate structure, take the now-obsolete `struct child' out of + the chain, and free its storage. + (execute_file_commands): Put all of the stuff invloving running the + commands into new function run_file_commands. Execute_file_commands + now does process management for the commands, while + run_file_commands (which is run in a subprocess) runs the commands. + (kill_children): New function to kill all running children by + sending them signal SIG. If there are any children still living + after they are all sent SIG, they are all sent SIGKILL. + + * make.c (main): Catch SIGCHLD (SIGCLD for USG) with child_handler. + + * commands.h: Declare child_handler function. + + * commands.c (execute_file_commands): Check the `command_state' + member of FILE and return 0 if it is `cs_running' or + `cs_deps_running' and return the stored status if it is `cs_finished'. + + * file.h (struct file): Added `command_state' member. + + * commands.c (execute_command_line): Add `$' to the list of + characters special to the shell. + +Wed Sep 21 15:57:41 1988 Roland McGrath (mcgrath at helen.Berkeley.EDU) + + * read.c (read_all_makefiles): Call convert_to_pattern before + recomputing the limits after adding the displaced rules. + + * make.c (main): Move calls to snap_deps, convert_to_pattern, and + build_vpath_lists to read_all_makefiles. + + * read.c (read_all_makefiles): Install the default pattern rules + before checking to remake the makefiles, displace these rules before + reading in the makefiles, and then add the displaced rules to the + chain after reading in all the makefiles. + + * make.c (main): Don't call install_default_pattern_rules or + count_implicit_rule_limits. + + * make.h: Declare displace_pattern_rules and + add_displaced_pattern_rules. + + * rule.c (displace_pattern_rules, add_displaced_pattern_rules): New + functions to stow the chain and add the stowed chain on the end of + the current chain. + + * make.texinfo (Implicit: Search Algorithm): Fixed PREV reference. + + * make.c (main): Call construct_include_path right after decoding + the switches. + + * read.c (find_makefile): Use rename_file. + + * file.h: Declare rename_file. + + * file.c (rename_file): New function to rename a `struct file' and + put it in the correct hash bucket. + + * read.c (find_makefile): New function to find and update a makefile. + (read_all_makefilese): Use find_makefile. + (read_makefile): Don't do updating. Removed UPDATEIT arg. + + * remake.c (update_file_1): Took out setting the `updated' member to + -1 rather than 1 sometimes. + + * make.c (main): Made it print version info before doing anything else. + + * remake.c (library_file_mtime, f_mtime): Removed use of last two + arguments to vpath_search. + + * rule.c (pattern_search): Removed use of last two arguments + to vpath_search. + + * vpath.c (vpath_search, selective_vpath_search): Removed unused + DIRPREFIX and DPLEN args. + + * read.c (read_makefile): Also turn off -n when updating makefiles. + +Tue Sep 20 17:01:10 1988 Roland McGrath (mcgrath at pepper.Berkeley.EDU) + + * Makefile: Put tags files in the tarfile. + + * read.c (read_makefile): Get the modtime of the makefile via a stat + call so that a later file_mtime call won't do VPATH search for it. + + * read.c (read_makefile): Don't turn off -t and -q if the makefile + was a command-line target. + + * make.c (main): Enter command-line targets as files and set their + `cmd_target' members. + + * file.h (struct file): Added `cmd_target' member. + + * read.c (read_makefile): Temporarily turn off -t and -q while + updating makefiles. + + * make.c (main): Don't use arg 0 from other_args (which is now + argv[0]; i.e., the program's name). + + * read.c (read_makefile): Only return nonzero if commands were + actually run to remake the makefile. + + * remake.c (update_file_1): Set FILE->updated to -1 if no commands + were actually run (because no update was done or -t was given). + + * make.c (decode_switches): Fixed bug wherein xrealloc was passed + bad args if it tried to expand other_args->list. + + * read.c (read_all_makefiles): Made it not look at the `MAKE' + variable, just use argv[0]. + +Sun Sep 18 17:34:11 1988 Roland McGrath (mcgrath at paris.Berkeley.EDU) + + * read.c (rerun_make): New function to re-exec make. + + * make.c (construct_makeflags, construct_argv): New functions to + construct the `MAKEFLAGS' variable and to construct an arg list from + parsed info. + + * read.c (read_makefile): New arg UPDATEIT, if nonzero, says to + update the makefile as a target before reading it in. When reading + included makefiles, pass this as zero. Now returns nonzero if the + makefile was updated, zero if not. + (read_all_makefiles): Pass a nonzero UPDATEIT arg to read_makefile + for all default and -f makefiles and all makefiles from the + `MAKEFILES' variable. If any of the makefiles has changed, re-exec + self to re-read them. + + * remake.c (update_file): Print a "File `foo' up to date'" message + under -p. + + * commands.c (execute_file_commands): Allocate one byte for each of + $^ and $< rather than zero if they are to be empty. + +Fri Sep 16 13:59:59 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * Version 3.06. + + * make.c (command_switches): Fixed entry for `-o' switch. + + * make.texinfo: Renamed -c switch to -C. + + * make.c: Renamed -c switch to -C. + + * Miscellaneous de-linting. + + * read.c (record_files): Made it not free the storage for the name + if it started with `./' and was therefore not quite the same as in + the `struct file'. + + * read.c (record_files): If commands were specified twice, the error + message specifies in what files and at what line numbers. + + * make.c (main): If any of the signals we usually fatal on were + ignored by the parent (probably a shell), ignore them. + + * make.c (main): Print version info for -v, -p, or -d. + (print_data_base): Don't print version info. It will be done in main. + + * variable.c: Increased number of hash buckets to 257. + + * file.c: Increased number of hash buckets to 1007. + + * rule.c (count_implicit_rule_limits): Moved comptation of + `maxsuffix' to convert_to_pattern, since that function uses + `maxsuffix', and must be called before count_implicit_rule_limits. + + * rule.c (pattern_search): If an existent (non-intermediate) + dependency was found via a terminal rule, set its + `tried_implicit' flag, so it will never have implicit rule search done. + + * glob.c: Bug fix to avoid alloca(0). + + * arscan.c: USG and Sun386i fixes. + +Thu Sep 15 19:40:26 1988 Roland McGrath (mcgrath at helen.Berkeley.EDU) + + * make.texinfo: Fixed some typos and spelling errors. + +Wed Sep 7 14:20:39 1988 Roland McGrath (mcgrath at helen.Berkeley.EDU) + + * make.c (decode_switches): Fixed bug wherein a bad option would + give a useless error message and loop forever. + +Tue Sep 6 14:36:02 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * make.texinfo: Documented `shell' function. + + * variable.c (expand_function): New function `shell', does + backquote-style command expansion of its arg. + + * commands.c (execute_command_line): Second arg OUTBUF, if not nil, + gets filled in with a malloc'd buffer containing the piped stdout of + the command. + (execute_file_commands): Use above (pass nil). + +Mon Sep 5 17:03:49 1988 Roland McGrath (mcgrath at hecuba.Berkeley.EDU) + + * Makefile: Added copyright notice. + Added a comment about defining `NO_MINUS_C_MINUS_O' if necessary. + + * Version 3.05. + + * rule.c (default_suffix_rules): Don't pass `-o' switches with `-c' + switches if `NO_MINUS_C_MINUS_O' is #define'd. + + * make.texinfo: Documented `GNUmakefile'. + + * read.c (read_all_makefiles): Made it try default makefile + `GNUmakefile' before others. + + * make.texinfo: Added new-style Texinfo header thingies. + +Sat Sep 3 18:09:39 1988 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * Version 3.04. + + * make.texinfo (Chained Rules): Added a @cindex about using + .PRECIOUS to preserve intermediate files. + + * remake.c (update_file_1): Made it not just return before executing + commands under -p. + + * rule.c (default_pattern_rules, default_variables): Made it use + `$(AR)' for `ar r' (to put files in archives). + + * vpath.c (build_vpath_lists): Made it recursively expand the + `VPATH' variable (by using variable_expand instead of lookup_variable). + + * read.c (conditional_line): Made it not swallow whitespace after + the comma in an `ifeq' using the `(a,b)' syntax. + + * rule.c (count_implicit_rule_limits): Made it not crash if a + pattern rule dep begins with `/'. + +Sun Aug 28 15:51:12 1988 Roland McGrath (mcgrath at homer.Berkeley.EDU) + + * make.texinfo: Clarified that the arg to the `origin' function is a + variable *name*, not a reference. + + * make.texinfo: Clarified that both -Idir and -I dir are allowed. + +Sat Aug 27 13:49:28 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * remake.c (remake_file): Made touching phonies work right. + +Wed Aug 24 20:40:48 1988 Roland McGrath (mcgrath at nutmeg.Berkeley.EDU) + + * make.texinfo: Removed reference to `RANLIB' variable. + + * Version 3.03. + + * variables.c (expand_function): Added `origin' function. + * make.texinfo: Documented same. + + * read.c (record_files): Made double-colon entries work. + +Sat Aug 20 21:09:39 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * make.c (collapse_continuations): Bug fix from RMS. + + * rule.c (install_default_pattern_rules): Made it set the + `in_use' flag of the created rules to zero, rather than letting + it be random garbage. + + * rule.c (pattern_search): Fixed putting `also make' targets into + file strucutres. + + * read.c (record_files): Fixed bug which made double-colon entries + make it read off into space. + + * make.c (decode_switches): Made it understand `ignored' switches + rather than dumping core. + +Sun Aug 14 16:49:00 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * read.c (read_makefile): Made `include' filenames be + variable-expanded. + + * read.c (read_makefile): Fixed an error message. + + * read.c (read_makefile): Made it accept ^L's as whitespace. + * make.c (next_token, end_of_token): Ditto. + + * vpath.c (vpath_search): Fixed it so that the general VPATH (from + the variable) is always checked, even if a selective VPATH (from a + directive) matched the filename. + +Sat Aug 13 14:20:46 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * make.c (decode_switches, main): Made the command switches be + processed from a table of switches, variables, and types. No + functions are passed argc and argv any more. They are passed arrays + of strings they need to process. + * read.c (read_all_makefiles): Made it take an array rather than + argc and argv. + (construct_include_path): Ditto. + + * make.c (collapse_continuations): Made it work right (I hope). + + * make.texinfo: Minor editorial changes. + + * read.c (read_makefile): Minor speed improvement by freeing and + then mallocing something rather than reallocing it to avoid the + unnecessary bcopy. + +Thu Aug 11 00:10:43 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * make.texinfo: Fixed some unquoted @'s. + + * make.texinfo: Documented multiple-target pattern rules. + Miscellaneous minor editorial changes and corrections. + + * make.texinfo (Implicit: Catalogue of Rules): Removed the list of + variables. That's what the next section is for. + (Implicit: Implicit Variables): Made it agree with reality. + +Wed Aug 10 00:55:39 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * variable.c (print_variable_data_base): Fixed bug which made -p + dump core. (This was a really idiotic bug.) + + * rule.c (pattern_search): Fixed a bug which made it make the + `also_make' member of the file in question nil if the first of + the successful rule's targets was the matching one. + Made it use only as much storage as necessary in the `also_make' + member. + (create_pattern): Made it use only as much storage as necessary in + the `lens' and `suffixes' members of the created rule. + + * remake.c (library_file_mtime): Made it `static'. + + * file.c: Added a declaration for `errno', which is declared in some + 's, but not all. + + * file.h (struct file): Added `also_make' member for multiple-target + implicit rules. + * rule.c (pattern_search): Made it put the names of files updated by + the given file's commands in its `also_make' member. + * remake.c (update_file_1): Made it mark the files in a file's + `also_make' member as updated when the file is updated. + + * variable.c (try_variable_definition): Fixed a bug which made it + define a variable with the name of the whole definition when there + was no space before the = or :=. + + * make.texinfo (Features): Made the changes which were made in RCS + revision 2.7 but somehow lost since then. Added -W. + +Tue Aug 9 10:04:50 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * variable.h: Added `o_default' to `enum variable_origin'. + * variable.c (print_variable_data_base): Made it print the origins of + the variables. + * rule.c (install_default_pattern_rules): Made it define the default + variables with origin `o_default'. + + * make.texinfo: Documented -W. + + * make.c (decode_switches, main): Added the -W flag to give files a + time-stamp of now, for a `what if' effect when used with -n. + + * commands.c (print_commands): Made it say `(built-in)' for commands + that are built into the default ruleset. + + * read.c (record_file): Made .SUFFIXES get its deps frontwards (again). + * rule.c (set_default_suffixes, convert_to_pattern): Made it read + .SUFFIXES's deps frontwards, so the converted rules will not be in + reverse order. + + * rule.c (new_pattern_rule): Fixed a bug wherein it would keep + searching after it had removed a matching rule and ended up diddling + with freed storage. + + * rule.c (freerule): Made it take the given rule off the chain. + (new_pattern_rule, count_implicit_rule_limits): Use freerule to + remove rules from the chain. + + * vpath.c (construct_vpath_list): Made it return after cleaning out + all previous searchpaths when given a nil DIRPATH arg, so it won't + go into the construction code and dump core dereferencing a nil + pointer. + + * variable.c (patsubst_expand): Fixed a bug which made it not match + correctly and sometimes dump core. + +Mon Aug 8 16:35:48 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * rule.c (default_suffix_rules): Made the .texinfo.dvi rule remove + the files used in the comparison to determine whether or not a + second TeX run is necessary. + + * make.texinfo: Fixed some overfull TeX hboxes. + + * make.texinfo (Implicit: Catalogue of Rules): Fixed a Texinfo error. + + * rule.c (create_pattern_rule): Fixed bug wherein index was not + being passed its second arg. + + * read.c (getline): Merged back into readline. + + * rule.c (default_suffixes, default_suffix_rules, + default_variables): Added .texinfo.info rule. + * make.texinfo (Implicit: Catalogue of Rules): Documented + .texinfo.dvi and .texinfo.info rules. + + * make.texinfo (Top): Changed `last updated' date to be correct (for + the last time it was updated, not today). Changed `for version + 3.00' since it's not going to be called that. + +Sat Aug 6 19:51:10 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * commands.c (print_commands): Added this function to print the + contents of a `struct commands' for -p. + * rule.c (print_rule_data_base): Use above. + * file.c (print_file_data_base): Ditto. + + * rule.c (count_implicit_rule_limits, new_pattern_rule, + install_pattern_rule, print_rule_data_base): Made it understand the + changed `struct rule' and act accordingly. + (freerule): Added this function to free all the storage used by a rule. + + * rule.c (pattern_search): Made it grok multiple targets of pattern + rules. The matching is done properly, but at present, only the + matching pattern's target is used to give deps and commands. + +Fri Aug 5 18:00:29 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * rule.c (struct rule): Changed name, namelen, and patsuffix members + to targets, lens, and suffixes, which are arrays, for multiple targets. + (create_pattern_rule): Now takes first arg TARGETS, a nil-terminated + array of targets, rather than a single target and patsuffix pointer. + + * read.c (record_files): If it finds an implicit pattern rule, it + collects all the targets into an array and passes the whole thing to + create_pattern_rule. If there are non-pattern targets, it is a + fatal error. + +Tue Aug 2 15:06:38 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * make.c (readline): Split backslash-newline checking from reading + and buffer-expanding. + (getline): Created to do the reading and buffer-expanding formerly + done in readline. + + * rule.c (pattern_search): Made it reject nonterminal match-anything + rules when a specific rule has matched, rather than rejecting + terminal match-anything rules in this case. + + * rule.c (convert_to_pattern): Fixed a bug caused when the change to + make it only recognize two-suffix rules whose target suffixes + precede their dependency suffixes which made it work in the opposite + direction (even worse than it started out). + + * rule.c (pattern_search): Made it reject nonterminal match-anything + rules as intermediate targets when searching for both real and + intermediate dependencies, rather than only when searching for + intermediate ones. + +Sun Jul 31 00:33:56 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * rule.c (convert_to_pattern): Made it only recognize two-suffix + rules whose target suffix comes before the dependency suffix in the + .SUFFIXES list. + + * variable.c (define_automatic_variables): Made all automatic + variables be defined with origin `o_automatic'. + + * variable.h: Added `o_automatic' to `enum variable_origin' + + * file.c (remove_intermediates): Made it not print an error message + if the error was that the file does not exist. + + * rule.c: Removed `recursive' member from `struct rule'. + + * remake.c (library_file_mtime): Made it not use the directory hash + functions, as reading in and hashing /usr/lib and /lib is slow and + most likely unnecessary. + + * remake.c (remake_file): Changed message from ``No specification + for making'' to ``No way to make'' so it will be short enough that + most filenames will fit on a line. + Made it look at the `recursive' member of the `struct commands', + rather than of the `struct file' (which no longer has one). + + * commands.c (execute_file_commands): Made it look at the + `recursive' member of the `struct commands', rather than of the + `struct file' (which no longer has one). + + * file.h: Removed `recursive' member from `struct file'. + + * commands.h: Added `recursive' member to `struct commands'. + + * dep.h: Removed unused `quotedparen' member from `struct nameseq' + and `struct dep'. + + * read.c (dequote): Removed this function. + (multi_glob): Removed reference to `quotedparen' member of + a `struct nameseq' and calls to dequote. + + * read.c (record_files): Made it set the stem for $* for all static + pattern rules, not just those with commands given at that time. + Removed check for recursive commands. + Made it check for pairs of .SUFFIXES dependencies to reject as + default goals as well as single ones (that don't start with dots). + (read_makefile): Added checks for recursive commands to set + the `recursive' flag in the `struct commands'. + +Sat Jul 30 15:47:23 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * make.c (find_next_token): Made the LENGTHPTR arg optionally nil. + + * make.c: Removed `files_made' variable which is defined static in + remake.c and used only there. + (main): Cleaned up somewhat. + (decode_switches): Cleaned up a bit. Made an unknown option be a + non-fatal error. + (decode_env_switches): Made LEN arg unsigned. Cleaned up. + (print_version): Made it say ``see the source'' rather than ``see + the source file'', since there is more than one. + + * file.h: Made `num_intermediates' declared unsigned. + + * file.c: Made `num_intermediates' variable unsigned. + (remove_intermediates): Removed unused FORMAT arg. + (enter_file): Made it handle double-colon files properly, adding the + new entry as the old entry's prev pointer. + + * dir.c: Re-indented the `struct dir' definition to be right. + (dir_load): Cleaned up slightly. + (file_exists_p): Removed comment saying we could use `access', since + that is a bad idea (except for setuid programs). Cleaned up slightly. + + * commands.c: Changed some comments slightly. + (execute_file_commands): Cleaned up a bit. Changed some comments, + added others. Moved freeing of storage for $^ and $? to the same + place as for the other automatic variables. + (execute_command_line): Made `#' trigger a shell. + Added some comments. Cleaned up a bit. Put all the special chars + that trigger shells into an array easily changeable at the top. + + * ar.c: Added comments explaining each function. + (ar_scan_1): Merged into ar_member_date. + (ar_member_date): Changed call to ar_scan_1 to the body of that + function. + (ar_member_date_1): Simplified to a ?: expression rather than an + if-else statement. + (ar_member_touch): Changed error handling around a bit. + None of these errors are fatal now. + + * variable.c (subst_expand): Added a new arg BY_WORD, to do substs + only on full words. + (patsubst_expand): Fixed bug which made calls whose patterns + contained no `%' to not work correctly, by using above. + (variable_expand): Pass extra arg to `subst_expand'. + + * variable.c (expand_function): Fixed bug which made `foreach' calls + with one-word lists run off into never-never land. + +Fri Jul 29 20:12:36 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * variable.c (expand_function): Made a very minor speed improvement + by avoiding an unnecessary strlen call. + +Wed Jul 27 16:01:47 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * rule.c (default_suffixes): Rearranged the list somewhat; added + `.el' and `.elc' to speed things up (especially when building + Emacs), for the same reason `.h' is there. + + * read.c (record_files): Changed `lineno' from `long' to + `unsigned int'. + +Sun Jul 24 02:15:30 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * variable.c (expand_function): Eliminated use of `wstok' + because it is non-reentrant and unreliable. + Fixed a minor bug which would cause something not to be freed. + * make.c (wstok): Removed `wstok' because it is no longer used. + + * variable.c (expand_function): Made `foreach' function put + spaces between output texts like it's supposed to. + +Sat Jul 23 17:32:55 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * rule.c (default_suffixes, default_suffix_rules): Added rule + to make %.dvi from %.texinfo. + + * dir.c (print_dir_data_base): Made it say a bit more. + +Fri Jul 22 23:13:16 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * make.c (print_data_base): Split this function up into one + for each thing. + * variable.c (print_variable_data_base): One of the above. + * rule.c (print_rule_data_base): Ditto. + * file.c (print_file_data_base): Ditto. + * dir.c (print_dir_data_base): Ditto. + + * rule.c (install_pattern_rule): Fixed a bug which caused the + terminal and recursive flags to always be zero for rules + entered by this function. + + * make.texinfo (Rules: Double-colon): Added a paragraph + explaining the purpose of double-colon rules. + + * make.texinfo (Implicit: Catalogue of Rules): Updated to + reflect new C++, TeX, Web, and Texinfo rules. Other slight + editorial changes. + + * commands.c (execute_file_commands): Fixed a bug wherein + random memory could get written for files with no deps. + +Wed Jul 20 19:30:31 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * read.c (readline): Fix bug wherein it would not recognize a + backslash-newline if the buffer filled up and was enlarged + right before reading the newline. + +Tue Jul 19 19:55:02 1988 Roland McGrath (mcgrath at chilli.Berkeley.EDU) + + * read.c: Added default suffix rules for .cc (using $(C++), + which defaults to `g++', and $(C++FLAGS)), .tex, .dvi, .web + and .cweb (using $(TEX), $(WEAVE), $(TANGLE), $(CWEAVE) and + $(CTANGLE)). + +Sat Jul 16 21:24:28 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * Made error formats use %u rather than %ld for line numbers, + which are now unsigned int's rather than long's. + + * read.c (conditional_line): Fixed some bugs caused by use of + unsigned int rather than int in one place. + + * read.c (conditional_line): Put the info about active + conditionals in a struct. + (read_makefile): Make a new struct of info about conditionals + for included makefiles and restore the old one after the + included makefile has been read. + + * read.c (read_makefile): Don't try to read a makefile with + name "" after giving an error message because an `include' + directive gave no filename. + + * read.c (read_makefile): Give an error message for + non-whitespace text after the filename in an `include' directive. + + * make.c (error): Take five args, like `fatal'. It managed to + lose with only two. Is there a better way to do this without vfprintf? + + * read.c (read_makefile): Commands consisting of only + whitespace are not the same as no commands. I thought I'd + fixed this bug months ago; it seems to have come back. + + * make.c (collapse_continuations): All whitespace around a + backslash-newline combination is turned into a single space. + + * Added COPYING file and copyright notices to all files. + + * make.texinfo (Running: Goals): Fix a typo. + + * read.c (do_define): Take an arg for the origin of the + variable being defined. + (read_makefile): Grok `override define'. + + * make.texinfo (Variables: Override Directive, Defining): + Document the `override define' combination directive. + + * ar.c (ar_member_date): Make a 0 return from `ar_scan' return + (time_t) -1 (nonexistent file), rather than (time_t) 0, which, + when put in the `struct file', makes `file_mtime' try to get + the mtime over and over again. + + * variable.c (pattern_matches): Fix a bug that made patterns + not beginning with `%' never match. + +Fri Jul 15 21:01:44 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU) + + * Took Make out of RCS. + + * Split the monolithic `make.c' into several smaller files. + + + +Copyright (C) 1988-2009 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . diff --git a/src/kmk/ChangeLog.2 b/src/kmk/ChangeLog.2 new file mode 100644 index 0000000..0816454 --- /dev/null +++ b/src/kmk/ChangeLog.2 @@ -0,0 +1,6653 @@ +2000-06-22 Paul D. Smith + + * job.c (start_job_command): Increment commands_started before the + special check for ":" (empty command) to avoid spurious "is up to + date" messages. Also move the test for question_flag after we + expand arguments, and only stop if the expansion provided an + actual command to run, not just whitespace. This fixes PR/1780. + +2000-06-21 Paul D. Smith + + * read.c (read_makefile): If we find a semicolon in the target + definition, remember where it was. If the line turns out to be a + target-specific variable, add back the semicolon and everything + after it. Fixes PR/1709. + +2000-06-19 Paul D. Smith + + * config.h-vms.template: #define uintmax_t for this system. + * config.ami.template: Ditto. + * config.h.W32.template: Ditto. + + * configure.in: We don't use select(2) anymore, so don't bother + checking for it. + * acconfig.h: Ditto. + * acinclude.m4: Ditto. + + * file.c (all_secondary): New static global; if 1 it means + .SECONDARY with no prerequisites was seen in the makefile. + (snap_deps): Set it appropriately. + (remove_intermediates): Check it. + (num_intermediates): Remove this global, it's not used anywhere. + (considered): Move this to remake.c and make it static. + + * NEWS: Document the change to .SECONDARY. + * make.texinfo (Special Targets): Document the change to .SECONDARY. + + * implicit.c (pattern_search): Remove the increment of + num_intermediates; it's not used. + * filedef.h: Remove num_intermediates and considered. + + * function.c (handle_function): If the last argument was empty, we + were pretending it didn't exist rather than providing an empty + value. Keep looking until we're past the end, not just at the end. + + * implicit.c (pattern_search): Multi-target implicit rules weren't + expanding the "also made" targets correctly if the pattern didn't + contain a slash but the target did; in that case the directory + part wasn't being added back to the stem on the "also made" + targets. Reported by Seth M LaForge , with + a patch. + +2000-06-17 Eli Zaretskii + + * Makefile.DOS.template (DESTDIR, bindir, datadir, libdir) + (infodir, mandir, includedir): Support installation under a + non-default DESTDIR. + + * remake.c (f_mtime): Fix the spelling of __MSDOS__. + + * configh.DOS.template (HAVE_FDOPEN, HAVE_MKSTEMP): Define. + +2000-06-14 Paul D. Smith + + * acinclude.m4 (pds_WITH_GETTEXT): rewrite fp_WITH_GETTEXT and + rename it to avoid confusion. This version is very specific: it + won't accept any gettext that isn't GNU. If the user doesn't + explicitly ask for the included gettext, we look to see if the + system gettext is GNU (testing both the actual libintl library, + and the libintl.h header file). Only if the system gettext is + really GNU gettext will we allow it to be used. + (pds_CHECK_SYSTEM_GETTEXT): A helper function. + +2000-06-13 Paul D. Smith + + * gettext.h: If we have libintl.h, use that instead of any of the + contents of gettext.h. We won't check for libintl.h unless we're + using the system gettext. + + * function.c (func_word): Clarify error message. + +2000-06-10 Paul Eggert + + Support nanosecond resolution on hosts with 64-bit time_t and + uintmax_t (e.g. 64-bit Sparc Solaris), by splitting + FILE_TIMESTAMP into a 30-bit part for nanoseconds, with the + rest for seconds, if FILE_TIMESTAMP is at least 64 bits wide. + + * make.h: Always define FILE_TIMESTAMP to be uintmax_t, for + simplicity. + + * filedef.h (FILE_TIMESTAMP_HI_RES, FILE_TIMESTAMP_LO_BITS) + (UNKNOWN_MTIME, NONEXISTENT_MTIME, OLD_MTIME) + (ORDINARY_MTIME_MIN, ORDINARY_MTIME_MAX): New macros. + (FILE_TIMESTAMP_STAT_MODTIME): Now takes fname arg. All uses changed. + (FILE_TIMESTAMP_DIV, FILE_TIMESTAMP_MOD) + (FILE_TIMESTAMP_FROM_S_AND_NS): Remove. + (FILE_TIMESTAMP_S, FILE_TIMESTAMP_NS): Use shifts instead of + multiplication and division. Offset the timestamps by + ORDINARY_MTIME_MIN. + (file_timestamp_cons): New decl. + (NEW_MTIME): Now just the maximal timestamp value, as we no longer use + -1 to refer to nonexistent files. + + * file.c (snap_deps, print_file): Use NONEXISTENT_MTIME, + UNKNOWN_MTIME, and OLD_MTIME instead of magic constants. + * filedef.h (file_mtime_1): Likewise. + * main.c (main): Likewise. + * remake.c (update_file_1, notice_finished_file, check_dep) + (f_mtime, name_mtime, library_search): Likewise. + * vpath.c (selective_vpath_search): Likewise. + + * remake.c (f_mtime): Do not assume that (time_t) -1 equals + NONEXISTENT_MTIME. When futzing with time stamps, adjust by + multiples of 2**30, not 10**9. Do not calculate timestamp + adjustments on DOS unless they are needed. + + * commands.c (delete_target): Do not assume that + FILE_TIMESTAMP_S yields -1 for a nonexistent file, as that is + no longer true with the new representation. + + * file.c (file_timestamp_cons): New function, replacing + FILE_TIMESTAMP_FROM_S_AND_NS. All uses changed. + (file_timestamp_now): Use FILE_TIMESTAMP_HI_RES instead of 1 < + FILE_TIMESTAMPS_PER_S to determine whether we're using hi-res + timestamps. + (print_file): Print OLD_MTIME values as "very old" instead of + as a timestamp. + +2000-05-31 Paul Eggert + + * remake.c (name_mtime): Check for stat failures. Retry if EINTR. + +2000-05-24 Paul D. Smith + + * main.c (decode_switches): The "positive_int" switch uses atoi() + which succeeds for any input, and doesn't notice if extra, + non-digit text is after the number. This causes make to mis-parse + command lines like "make -j 5foo" as "make -j5" (ignoring "foo" + completely) instead of "make -j0 5foo" (where "5foo" is a + target). Fix this by checking the value by hand. We could use + strtol() if we were sure of having it; this is the only + questionable use of atoi() I found so we'll just stick with that. + Fixes PR/1716. + + * i18n/ja.po, i18n/nl.po, i18n/pt_BR.po: New translation files. + * configure.in (ALL_LINGUAS): Added pt_BR. + +2000-05-22 Paul Eggert + + * remake.c (f_mtime): Fix bug when handling future odd + timestamps in the WINDOWS32 case. Do not bother initializing + static var to zero. Simplify code that works around WINDOWS32 + and __MSDOS__ time skew brain damage. + +2000-05-22 Paul Eggert + + * job.c: Don't include time.h, as make.h already does this. + +2000-05-22 Paul Eggert + + * configure.in (AC_CHECK_HEADERS): Add sys/time.h. + (AC_HEADER_TIME): Add. + (clock_gettime): Prefer -lrt to -lposix4, for Solaris 7. + (gettimeofday): Add check for standard version of gettimeofday. + This merges changes written by Paul D. Smith. + + * file.c (file_timestamp_now): Use gettimeofday if available + and if clock_gettime does not work. Don't bother with + high-resolution clocks if file timestamps have only one-second + resolution. + + * make.h : Include, conditionally on the usual + TIME_WITH_SYS_TIME and HAVE_SYS_TIME_H macros. This is needed + for gettimeofday. + +2000-05-20 Paul D. Smith + + * read.c (read_makefile): We weren't keeping makefile names around + unless there was a rule defined in them; but now we need to keep + them for variables as well. Forget trying to be fancy: just keep + every makefile name we successfully open. + + * remote-cstms.c (start_remote_job_p): Change DB_EXTRA (?) to DB_JOBS. + +2000-05-17 Paul Eggert + + * commands.c (chop_commands): Ensure ctype macro args are nonnegative. + * expand.c (variable_expand_string): Likewise. + * function.c (subst_expand, lookup_function, msdos_openpipe): + Likewise. + * job.c (vms_redirect, start_job_command, new_job, child_execute_job, + construct_command_argv_internal, construct_command_argv): Likewise. + * main.c (decode_env_switches, quote_for_env): Likewise. + * misc.c (collapse_continuations, end_of_token, end_of_token_w32, + next_token): Likewise. + * read.c (read_makefile, do_define, conditional_line, + find_char_unquote,get_next_mword): Likewise. + * variable.c (try_variable_definition): Likewise. + * vpath.c (construct_vpath_list): Likewise. + * w32/pathstuff.c (convert_vpath_to_windows32): Likewise. + +2000-05-10 Eli Zaretskii + + * main.c (main) [__MSDOS__]: Add SIGFPE to signals we block when + running child programs, to prevent Make from dying on Windows 9X + when the child triggers an FP exception. + +2000-05-08 Paul D. Smith + + * dir.c (find_directory) [WINDOWS32]: If we strip a trailing "\" + from the directory name, remember to add it back. The argument + might really be inside a longer string (e.g. %Path%) and if you + don't restore the "\" it'll be truncated permanently. Fixes PR/1722. + Reported by + +2000-05-02 Paul D. Smith + + * job.c (construct_command_argv_internal) [WINDOWS32]: Added "rd" + and "rmdir" to the list of command.com commands. + Reported by Elod Horvath + +2000-04-24 Paul D. Smith + + * i18n/ja.po: New translation file from the Japanese language team. + +2000-04-18 Paul D. Smith + + * remake.c (f_mtime): If ar_member_date() returns -1 (the member + doesn't exist), then return (FILE_TIMESTAMP)-1 rather than + returning the timestamp calculated from the value -1. Fixes PR/1696. + Reported by Gilles Bourhis . + +2000-04-17 Paul D. Smith + + * config.h.W32.template: Add LOCALEDIR macro resolving to "". + * w32/subproc/sub_proc.c (process_begin): Remove reference to + debug_flag; change it to a DB() call. Fixes PR/1700. + Reported by Jim Smith + +2000-04-17 Bruno Haible + + * arscan.c [BeOS]: Add replacement for nonexistent from GNU + binutils. + +2000-04-11 Paul D. Smith + + * function.c (expand_builtin_function): If no arguments were + provided, just quit early rather than changing each function to + test for this. + (function_table[]): Change the min # of arguments to 0 for all + those functions for which it makes sense (currently everything + that used to take a minimum of 1 argument, except $(call ...)). + Fixes PR/1689. + +2000-04-09 Eli Zaretskii + + * README.DOS: Add instructions to install a binary distro. + Mention latest versions of Windows. + +2000-04-07 Eli Zaretskii + + * main.c (main): Rename TMP_TEMPLATE into DEFAULT_TMPDIR, and use + it for the directory of the temporary file. If P_tmpdir is + defined, use it in preference to "/tmp/". Try $TMPDIR, $TEMP, and + $TMP in the environment before defaulting to DEFAULT_TMPDIR. + (print_version): Add year 2000 to the Copyright line. + +2000-04-04 Paul D. Smith + + * Version 3.79 released. + + * make.texinfo: Update documentation with new features for 3.79. + + * function.c (func_wordlist): Don't re-order arguments to + wordlist. + +2000-04-03 Paul D. Smith + + * remake.c (f_mtime): Archive member timestamps are stored as + time_t, without nanoseconds. But, f_mtime() wants to return + nanosecond info on those systems that support it. So, convert the + return value of ar_member_date() into a FILE_TIMESTAMP, using 0 as + the nanoseconds. + +2000-03-28 Paul D. Smith + + * Version 3.78.92 released. + + * build.template: Updates for gettext support; some bugs fixed. + +2000-03-27 Paul D. Smith + + * config.guess, config.sub: Updated from config CVS archive at + :pserver:anoncvs@subversions.gnu.org:/home/cvs as of today. + + * read.c (record_files): Check if expanding a static pattern + rule's prerequisite pattern leaves an empty string as the + prerequisite, and issue an error if so. Fixes PR/1670. + (read_makefile): Store the starting linenumber for a rule in + TGTS_STARTED. + (record_waiting_files): Use the TGTS_STARTED value for the file + location passed to record_file() instead of the current + linenumber, so error messages list the line where the target was + defined instead of the line after the end of the rule definition. + + * remake.c (start_updating, finish_updating, is_updating): Fix + PR/1671; circular dependencies in double-colon rules are not + diagnosed. These macros set the updating flag in the root + double-colon file instead of the current one, if it's part of a + double-colon list. This solution provided by Tim Magill + ; I just changed the macro names :). + (update_file_1): Call them. + (check_dep): Call them. + + The change to not automatically evaluate the $(call ...) + function's arguments breaks recursive use of call. Although using + $(if ...) and $(foreach ...) in $(call ...) macros is important, + the error conditions generated are simply to obscure for me to + feel comfortable with. If a method is devised to get both + working, we'll revisit. For now, remove this change. + + * function.c (function_table): Turn on the expand bit for func_call. + (func_call): Don't expand arguments for builtin functions; that + will have already been done. + +2000-03-26 Paul D. Smith + + * file.c (remove_intermediates): Never remove targets explicitly + requested on the command-line by checking the cmd_target flag. + Fixed PR/1669. + +2000-03-23 Paul Eggert + + * filedef.h (FILE_TIMESTAMP_STAT_MODTIME): Use st_mtime instead of + st_mtim.tv_sec; the latter doesn't work on Unixware. + +2000-03-18 Paul D. Smith + + * file.c (file_hash_enter): If we're trying to change a file into + itself, just return. We used to assert this wasn't true, but + someone came up with a weird case involving archives. After + playing with it for a while I decided it was OK to ignore it. + + * default.c: Define COFLAGS to empty to avoid spurious warnings. + + * filedef.h: Change #if ST_MTIM_NSEC to #ifdef; this is a macro + containing the name of the nsec field, not true/false. + * make.h: Ditto. + Reported by Marco Franzen . + +2000-03-08 Tim Magill + + * remake.c (update_file): Return the exit status of the pruned + file when pruning, not just 0. Fixes PR/1634. + +2000-02-24 Paul D. Smith + + * configure.in: Close a minor potential security hole; if you're + reading makefiles from stdin (who does that?) you could run into a + race condition with the temp file using mktemp() or tmpnam(). Add + a check for mkstemp() and fdopen(). + * main.c (open_tmpfile): New function to open a temporary file. + If we have mkstemp() (and fdopen()), use that. If not use + mktemp() or tmpnam(). If we have fdopen(), use open() to open the + file O_CREAT|O_EXCL. If not, fall back to normal fopen() (insecure). + (main): Call it. + * job.c (child_execute_job) [VMS]: Call it. + + * variable.c (lookup_variable): If we find a variable which is + being expanded, then note it but keep looking through the rest of + the set list to see if we can find one that isn't. If we do, + return that. If we don't, return the original. Fix for PR/1610. + + While implementing this I realized that it also solves PR/1380 in + a much more elegant way. I don't know what I was smoking before. + So, remove the hackage surrounding the original fix for that (see + below). Change this function back to lookup_variable and remove + the extra setlist argument. + * variable.h (recursively_expand_setlist): Remove the macro, + rename the prototype, and remove the extra setlist argument. + (lookup_variable): Ditto. + * expand.c (recursively_expand): Rename and remove the extra + setlist argument. + (reference_variable): Use lookup_variable() again. + (allocated_variable_append): Remove the extra setlist argument. + +2000-02-21 Paul D. Smith + + * README.template: A few updates. + + * i18n/de.po: New version from the German translation team. + +2000-02-09 Paul D. Smith + + * Version 3.78.91 released. + +2000-02-07 Paul D. Smith + + * read.c (read_makefile): Reset *p2 to ':', not *colonp. If any + filenames contained backslashes the resulting output (without + backslashes) will be shorter, so setting *colonp doesn't change + the right character. Fix for PR/1586. + + For += target-specific variables we need to remember which + variable set we found the variable in, so we can start looking + from there in the next iteration (otherwise we might see it again + in recursively_expand and fail!). This is turning into a hack; if + it gets any worse we'll have to rethink this entire algorithm... + implementing expansion of these references separately from the + "normal" expansion, say, instead of using the same codepath. + Actually, it's already "worse enough" :-/. + Fix for PR/1380. + + * variable.h (recursively_expand_setlist): Rename + recursively_expand to add a struct variable_set_list argument, and + make a macro for recursively_expand. + (lookup_variable_setlist): Rename lookup_variable to add a struct + variable_set_list argument, and make a macro for lookup_variable. + + * expand.c (recursively_expand_setlist): Take an extra struct + variable_set_list argument and pass it to allocated_variable_append(). + (reference_variable): Use lookup_variable_setlist() and pass the + returned variable_set_list to recursively_expand_setlist. + (allocated_variable_append): Take an extra setlist argument and + use this as the starting place when searching for the appended + expansion. If it's null, use current_variable_set_list as before. + + * variable.c (lookup_variable_setlist): If the LISTP argument is + not nil, set it to the list containing the variable we found. + +2000-02-04 Paul D. Smith + + * variable.c (print_variable): Write out filename/linenumber + information for the variable definition if present. + (define_variable_in_set): Store filename information if provided. + (define_variable, define_variable_for_file): Removed. + (try_variable_definition): Use define_variable_loc() to keep + variable definition location information. + * read.c (read_makefile): Keep variable definition location info. + (do_define): Ditto. + (record_target_var): Ditto. + * variable.h (define_variable_in_set): New fileinfo argument. + (define_variable, define_variable_loc, define_variable_for_file): + Declare new macros. + + Fix PR/1407: + + * filedef.h (struct file): Rename patvar to pat_variables and make + it just a variable_set_list; we need our own copy of the pattern + variable's variable set list here to avoid overwriting the global + one. + * variable.c (initialize_file_variables): Move the instantiation + of the pat_variables pointer here. Only do the search after we're + done reading the makefiles so we don't search too early. If + there's a pat_variables value, set up the variables next ptr. + * expand.c (variable_expand_for_file): Remove the setup of the + pat_variables info; it's done earlier now to ensure the parent's + pattern variables are set up correctly as well. + +2000-02-03 Paul D. Smith + + * job.c (sh_chars_dos) [WINDOWS32]: Add "&" as a shell + metacharacter for the W32 DOS shell. + Reported by Warren Jones . + +2000-02-02 Paul D. Smith + + Fixes for the OpenVMS port from Hartmut Becker + + * config.h-vms [VMS]: Define LOCALEDIR to something; needed for + the expansion of bindtextdomain() even though it's a no-op. + * vmsfunctions.c (strcmpi): Remove duplicate definition of strcmpi(). + (readdir): Use DB() instead of testing debug_flag. + * dir.c (file_impossible) [VMS]: Search "p" not "name". + * job.c [VMS]: Switch from debug_flag to the new DB macro. Add + some i18n _() macros (even though VMS doesn't yet support it). + + * function.c (patsubst_expand): Change "len" to not be unsigned to + avoid type mismatches. + + * main.c (main): Declare signame_init() if we're going to call it. + +2000-01-29 Eli Zaretskii + + * Makefile.DOS.template: Track changes in Makefile.in + (install-recursive, uninstall-recursive): Add missing targets. + (DESTDIR): Define. + (install-binPROGRAMS, uninstall-binPROGRAMS): Use $(DESTDIR). + + * default.c (default_variables) [__MSDOS__]: Define CXX to gpp. + +2000-01-27 Paul D. Smith + + * gettext.c: Some warning cleanups, and a fix for systems which + don't define HAVE_ALLOCA (the workaround code was included + twice). + +2000-01-26 Paul D. Smith + + * Version 3.78.90 released. + +2000-01-25 Paul D. Smith + + Change gettext support to use the simplified version in libit 0.7. + + * getopt.c, make.h: Use gettext.h instead of libintl.h. + * ABOUT-NLS, gettext.h, gettext.c: New files from libit 0.7. + Modified to remove some static declarations which aren't defined. + * acconfig.h: Use new gettext #defines. + * acinclude.m4: Add fp_WITH_GETTEXT; remove AM_GNU_GETTEXT. + * configure.in: Call fp_WITH_GETTEXT instead. + * Makefile.am: New gettext stuff. Also force inclusion of glob + files for systems which have LIBC glob. + + * i18n/Makefile.am, i18n/.cvsignore: New dir for translation files. + * i18n/de.po, i18n/es.po, i18n/fr.po, i18n/ko.po, i18n/nl.po: + * i18n/pl.po, i18n/ru.po: Import translations already done for + earlier versions of GNU make. Thanks for that work!! + + * po/Makefile.in.in, po/POTFILES.in: Removed. + +2000-01-23 Paul D. Smith + + * main.c (decode_debug_flags): If debug_flag is set, enable all + debugging levels. + (debug_flag): Resurrect this flag variable. + (switches): Make -d give the old behavior of turning on all + debugging. Change --debug alone to emit basic debugging and take + optional arguments to expand debugging. + * NEWS: Document the new debugging options. + + * remake.c (no_rule_error): Remove this function. This tries to + fix a real problem--see the description with the introduction of + this function below. However, the cure is worse than the disease + and this approach won't work. + (remake_file): Put the code from no_rule_error back here. + (update_file_1): Remove call to no_rule_error. + + * filedef.h (struct file): Remove mfile_status field. + +2000-01-22 Paul D. Smith + + Integrate GNU gettext support. + + * configure.in: Add AM_GNU_GETTEXT. + * Makefile.am: Add options for setting LOCALEDIR, -Iintl, etc. + * acinclude.m4: Add gettext autoconf macros. + * acconfig.h: Add new gettext #defines. + * make.h: Include libintl.h. Make sure _() and N_() macros are + declared. Make gettext() an empty macro is NLS is disabled. + * main.c (struct command_switch switches[]): Can't initialize + static data with _() (gettext calls), so use N_() there then use + gettext() directly when printing the strings. + * remake.c (no_rule_error): The string constants can't be static + when initializing _() macros. + * file.c (print_file): Reformat a few strings to work better for + translation. + * po/POTFILES.in, po/Makefile.in.in: New files. Take + Makefile.in.in from the latest GNU tar distribution, as that + version works better than the one that comes with gettext. + * NEWS: Mention i18n ability. + +2000-01-21 Paul D. Smith + + Installed patches for the VMS port. + Patches provided by: Hartmut Becker + + * readme.vms, arscan.c, config.h-vms, default.c, dir.c, file.c: + * implicit.c, job.c, make.h, makefile.com, makefile.vms, rule.c: + * variable.c, vmsdir.h, vmsfunctions.c, vmsify.c, glob/glob.c: + * glob/glob.h: Installed patches. See readme.vms for details. + +2000-01-14 Andreas Schwab + + * dir.c (read_dirstream): Initialize d_type if it exists. + +2000-01-11 Paul D. Smith + + Resolve PR/xxxx: don't automatically evaluate the $(call ...) + function's arguments. While we're here, clean up argument passing + protocol to always use simple nul-terminated strings, instead of + sometimes using offset pointers to mark the end of arguments. + This change also fixes PR/1517. + Reported by Damien GIBOU . + + * function.c (struct function_table_entry): Remove the negative + required_args hack; put in explicit min and max # of arguments. + (function_table): Add in the max value. Turn off the expand bit + for func_call. + (expand_builtin_function): Test against minimum_args instead of + the obsolete required_args. + (handle_function): Rewrite this. We don't try to be fancy and + pass one style of arguments to expanded functions and another + style to non-expanded functions: pass pointers to nul-terminated + strings to all functions. + (func_call): Rewrite this. If we are invoking a builtin function + and it's supposed to have its arguments expanded, do that (since + it's not done by handle_function for $(call ...) anymore). For + non-builtins, just add the variables as before but mark them as + recursive so they'll be expanded later, as needed. + (func_if): All arguments are vanilla nul-terminated strings: + remove trickery with "argv[1]-1". + (func_foreach): Ditto. + + * expand.c (expand_argument): If the second arg is NULL, expand + the entire first argument. + + * job.c (new_job): Zero the child struct. This change was just + made to keep some heap checking software happy, not because there + was an actual bug (the important memory was being cleared properly). + +1999-12-15 Paul D. Smith + + * variable.c (print_variable): Print the variable with += if the + append flag is set. + + * implicit.c (pattern_search): Remove the extra check of the + implicit flag added on 8/24/1998. This causes problems and the + reason for the change was better resolved by the change made to + check_deps() on 1998-08-26. This fixes PR/1423. + +1999-12-08 Paul D. Smith + + * dir.c (dir_setup_glob): On 64 bit ReliantUNIX (5.44 and above) + in LFS mode, stat() is actually a macro for stat64(). Assignment + doesn't work in that case. So, stat is a macro, make a local + wrapper function to invoke it. + (local_stat): Wrapper function, if needed. + Reported by Andrej Borsenkow . + +1999-12-02 Paul D. Smith + + * remake.c (update_file): Move the considered test outside the + double-colon loop, _but_ make sure we test the double_colon target + not the "current" target. If we stop early because one + double-colon target is running, mark all the rest considered and + try to start their prerequisites (so they're marked considered). + Fix for PR/1476 suggested by Tim Magill . + +1999-11-22 Rob Tulloh + + * function.c (windows32_openpipe, func_shell): Correct Windows32 + problem where $(shell nosuchfile) would incorrectly exit make. The + fix is to print the error and let make continue. + Reported by David Masterson . + + * w32/subproc/misc.c (arr2envblk): Memory leak fix. + +1999-11-21 Paul D. Smith + + Rework GNU make debugging to provide different levels of output. + + * NEWS: mention it. + * debug.h: New file. Define various debugging levels and macros. + * function.c, implicit.c, job.c, main.c, misc.c, read.c, remake.c + * remote-cstms.c, vmsfunctions.c: Replace all code depending on + debug_flag with invocations of debugging macros. + * make.h: Remove debug_flag and DEBUGPR, add db_level. + +1999-11-18 Paul Eggert + + * acinclude.m4 (AC_SYS_LARGEFILE_FLAGS): Work around a problem + with the QNX 4.25 shell, which doesn't propagate exit status of + failed commands inside shell assignments. + +1999-11-17 Paul D. Smith + + * function.c (func_if): Find the end of the arg list by testing + the next item for NULL; any other test is not correct. + Reported by Graham Reed (PR/1429). + + Fix += when used in a target-specific variable context. + + * variable.h: New bitfield APPEND set if we have a += + target-specific variable. + + * variable.c (try_variable_definition): Add an argument to specify + if we're trying a target-specific variable. If we are and it's an + append style, don't append it, record it as normal recursive, but + set the APPEND flag so it'll be expanded later. + * main.c (handle_non_switch_argument): Use new + try_variable_definition() signature. + * read.c (read_makefile,record_target_var): Ditto. + + * expand.c (allocated_variable_append): New function: like + allocated_variable_expand(), but we expand the same variable name + in the context of the ``next'' variable set, then we append this + expanded value. + (recursively_expand): Invoke it, if the APPEND bit is set. + +1999-11-10 Paul D. Smith + + * file.c (snap_deps): If the .NOTPARALLEL target is defined, turn + off parallel builds for this make only (still allow submakes to be + run in parallel). + * main.c: New variable, ``not_parallel''. + * make.h: Add an extern for it. + * job.c (new_job): Test NOT_PARALLEL as well as JOB_SLOTS. + * NEWS: Add info on .NOTPARALLEL. + * make.texinfo (Special Targets): Document it. + + * configure.in (GLOBDIR): Set to "glob" if we need to build the + glob library. + * Makefile.am (SUBDIRS): Use the GLOBDIR variable instead of + "glob" so we don't try to build glob if we don't need to (if we + have GLIBC glob). Reported by Lars Hecking . + + * main.c (main): Don't put "***" in the clock skew warning + message. Reported by karl@gnu.org. + + * make.h: Remove unneeded signal setup. + + * signame.c: Remove extraneous #includes; some versions of Ultrix + don't protect against multiple inclusions and it causes compile + errors. Reported by Simon Burge . + +1999-10-15 Paul D. Smith + + * main.c (quote_for_env): Rename from quote_as_word(). + + * make.h, *.c: Prefer strchr() and strrchr() in the code + rather than index() and rindex(). Define strchr/strrchr in terms + of index/rindex if the former aren't supported. + + * default.c (CHECKOUT,v): Replace the fancy, complicated + patsubst/filter expression with a simple $(if ...) expression. + + * main.c (print_usage): Add the bug reporting mailing address to + the --help output, as per the GNU coding standards. + Reported by Paul Eggert . + + * README.customs: Installed information on running Customs-ized + GNU make and setuid root, collected by Ted Stern . + + * read.c (read_all_makefiles): PR/1394: Mark the end of the next + token in the MAKEFILES value string _before_ we dup it. + +1999-10-13 Paul D. Smith + + * configure.in (make_cv_sys_gnu_glob): We used to add the -Iglob + flag to CPPFLAGS, but that loses if the user specifies his own + CPPFLAGS; this one gets added _after_ his and if he happens to + have an old or broken glob.h--boom. Instead, put it in GLOBINC + and SUBST it. + + * Makefile.am (INCLUDES): Add @GLOBINC@ to the INCLUDES macro; + these things get on the compile line well before the user's + CPPFLAGS. + +1999-10-12 Paul D. Smith + + * remake.c (notice_finished_file): If we get here and -n is set, + see if all the command lines are marked recursive. If so, then we + ran every command there is, so check the mtime on this file just + like we would normally. If not, we assume the command we didn't + run would updates the target and set mtime of the target to "very new". + + * job.c (start_job_command): Update lines_flags in the file's cmds + structure with any per-line tokens we found (`@', `-', `+'). + +1999-10-08 Paul D. Smith + + * variable.c (initialize_file_variables): Always recurse to + initialize the parent's file variables: the parent might not have + any rules to run so it might not have been initialized before + this--we need this to set up the chain properly for + target-specific variables. + +1999-09-29 Paul Eggert + + * main.c (quote_as_word): Always quote for decode_env_switches + instead of for the shell, so that arguments with strange + characters are are passed to submakes correctly. Remove + double_dollars arg; we always double dollars now. All callers + changed. + (decode_env_switches): Don't run off the end of an environment + variable whose contents ends in a unescaped backslash. + +1999-09-23 Paul D. Smith + + * commands.c, function.c, job.c, read.c: Cast arguments to + ctype.h functions/macros to _unsigned_ char for portability. + + * remake.c, function.c: Compiler warning fixes: the second + argument to find_next_token() should be an _unsigned_ int*. + Reported by Han-Wen Nienhuys . + +1999-09-23 Paul D. Smith + + * Version 3.78.1 released. + + * make.texinfo: Update version/date stamp. + + * main.c (main): Argh. For some reason we were closing _all_ the + jobserver pipes before we re-exec'd due to changed makefiles. + This means that any re-exec got a "jobserver unavailable" error :-/. + I can't believe we didn't notice this before. + +1999-09-22 Paul D. Smith + + * Version 3.78 released. + + * main.c (main): Only fail on multiple --jobserver-fds options if + they aren't all the same. Some makefiles use things like + $(MAKE) $(MFLAGS) which will cause multiple, identical copies of + --jobserver-fds to show up. + +1999-09-16 Paul D. Smith + + * main.c (define_makeflags): Zero out FLAGSTRING to avoid + uninitialized memory reads when checking *p != '-' in the loop. + +1999-09-15 Paul D. Smith + + * Version 3.77.97 released. + + * configure.in (MAKE_HOST): AC_SUBST this so it will go into the + makefile. + * Makefile.am (check-local): Print a success banner if the check + succeeds. + (check-regression): A bit of fine-tuning. + +1999-09-15 Eli Zaretskii + + * README.DOS.template: Document requirements for the test suite. + * Makefile.DOS.template: Updates to allow the test suite to run + from "make check". + + * main.c (main): Handle it if argv[0] isn't an absolute path. + +1999-09-13 Paul D. Smith + + * Version 3.77.96 released. + + * Makefile.am (loadavg): Use CPPFLAGS, etc. to make sure we get + all the right #defines to compile. + (check-regression): Look for the regression test suite in the make + package itself. If we're building remotely, use symlinks to make + a local copy. + (dist-hook): Put the test suite into the tar file. + + * configure.in: Look for perl for the test suite. + +1999-09-10 Paul Eggert + + * acinclude.m4 (AC_SYS_LARGEFILE_FLAGS): If on HP-UX 10.20 or + later, and using GCC, define __STDC_EXT__; this works around a + bug in GCC 2.95.1. + +1999-09-08 Paul D. Smith + + * main.c (print_version): Ugh. GLIBC's configure tries to check + make version strings and is too aggressive with their matching + expressions. I've struck a deal with them to leave the version + output as-is for 3.78, and they'll change their configure checks + so that I can change this back in the future. + +1999-09-07 Eli Zaretskii + + * job.c (construct_command_argv_internal) [__MSDOS__]: Add "echo" + and "unset" to the list of builtin shell commands. + + * configh.DOS.template (MAKE_HOST): Define to "i386-pc-msdosdjgpp" + which is the canonical name of the DJGPP host. + +1999-09-05 Paul D. Smith + + * Version 3.77.95 released. + + * make.texinfo (Make Errors): Document some new jobserver error + messages. + +1999-09-04 Eli Zaretskii + + * make.texinfo (Make Errors): Document the hint about 8 spaces + instead of a TAB. + (Call Function, Quick Reference): Use @code{$(1)}, not @var. + + * main.c (main) [__MSDOS__]: Say "on this platform" instead of "on + MS-DOS", since the MSDOS version could run on Windows. + +1999-09-03 Paul D. Smith + + * remake.c (notice_finished_file): Always set mtime_before_update + if it's not been set, not just if we ran some rules. Otherwise we + may have a situation where a target's prerequisite was rebuilt but + not changed, so this target's rules weren't run, then + update_goal_chain() sees mtime_before_update != last_mtime and + thinks that the top-level target changed when it really didn't. + This can cause an infinite loop when remaking makefiles. + (update_goal_chain): If we get back to the top and we don't know + what the goal's last_mtime was, find it now. We need to know so + we can compare it to mtime_before_update later (this is only + crucial when remaking makefiles--should we only do it then?) + +1999-09-02 Paul D. Smith + + * read.c (read_makefile): If "override" appears as the first + prerequisite, look further to ensure this is really a + target-specific variable definition, and not just some + prerequisite named "override". + +1999-09-01 Paul D. Smith + + * function.c (IS_PATHSEP) [WINDOWS32]: Allow backslash separators + for W32 platforms. + * read.c (record_files) [WINDOWS32]: Allow backslash separators + for W32 platforms. + * implicit.c (pattern_search) [WINDOWS32]: Allow backslash + separators for W32 platforms. + + * configure.in (MAKE_HOST): Define it to be the canonical build + host info, now that we need AC_CANONICAL_HOST anyway (for large + file support). + * version.c (make_host): Define a variable to MAKE_HOST so we're + sure to get it from the local config.h. + * main.c (print_version): Use it in the version information. + * config.ami.template: Add MAKE_HOST. + * configh.dos.template: Ditto. + * config.h.W32.template: Ditto. + * config.h-vms.template: Ditto. + + * main.c (main): Close the jobserver file descriptors if we need + to re-exec ourselves. + Also print more reasonable error if users force -jN for submakes. + This may be common for a while until people use the jobserver + feature. If it happens, we ignore the existing jobserver stuff + and use whatever they specified on the commandline. + (define_makeflags): Fixed a long-standing bug: if a long name + only option comes immediately after a single letter option with no + argument, then the option string is constructed incorrectly. For + example, with -w and --jobserver-fds you get "-w-jobserver-fds..." + instead of "-w --jobserver-fds..."; add in an extra " -". + + * make.texinfo (Phony Targets): Add another example of using + .PHONY with subdirectories/recursive make. + +1999-08-30 Paul D. Smith + + * README.W32.template: Renamed from README.W32 so it's + autogenerated during the dist. A few minor modifications. + + * configure.in: Check for kstat_open before AC_FUNC_GETLOADAVG + since the latter needs to know whether the former exists to give + an accurate result. + +1999-08-26 Rob Tulloh + + * NMakefile [WINDOWS32]: Now more robust. If you change a file + under w32/subproc, the make.exe will be relinked. Also added some + tests to make sure erase commands won't fail when executed in a + pristine build environment. + + * w32/subproc/sub_proc.c [WINDOWS32]: Added support for + HAVE_CYGWIN_SHELL. If you are using the Cygwin B20.1 release, it + is now possible to have have native support for this shell without + having to rely on klutzy BATCH_MODE_ONLY_SHELL. + + * config.h.W32 [WINDOWS32]: Added HAVE_CYGWIN_SHELL macro which + users can define if they want to build make to use this shell. + + * README.W32 [WINDOWS32]: Added informaton about + HAVE_CYGWIN_SHELL. Cleaned up text a bit to make it more current. + +1999-08-26 Paul Eggert + + Support large files in AIX, HP-UX, and IRIX. + + * acinclude.m4 (AC_LFS): Remove. Superseded by AC_SYS_LARGEFILE. + (AC_SYS_LARGEFILE_FLAGS, AC_SYS_LARGEFILE_SPACE_APPEND, + AC_SYS_LARGEFILE_MACRO_VALUE, AC_SYS_LARGEFILE): New macros. + (jm_AC_TYPE_UINTMAX_T): Check for busted compilers that can't + shift or divide unsigned long long. + (AM_PROG_CC_STDC): New macro; a temporary workaround of a bug in + automake 1.4. + + * configure.in (AC_CANONICAL_HOST): Add; required by new + AC_SYS_LARGEFILE. + (AC_SYS_LARGEFILE): Renamed from AC_LFS. + (AM_PROG_CC_STDC): Add. + + * config.guess, config.sub: New files, needed for AC_CANONICAL_HOST. + +1999-08-25 Paul Eggert + + * make.h (CHAR_MAX): New macro. + * main.c (struct command_switch): c is now int, + so that it can store values greater than CHAR_MAX. + (switches): Replace small numbers N with CHAR_MAX+N-1, + to avoid problems with non-ASCII character sets. + (short_option): New macro. + (init_switches, print_usage, define_makeflags): Use it instead of + isalnum. + +1999-08-25 Paul D. Smith + + * Version 3.77.94 released. + + * main.c (main) [__MSDOS__]: If the user uses -j, warn that it's + not supported and reset it. + + * make.h (ISDIGIT): Obtained this from the textutils distribution. + * main.c (decode_switches): Use it. + * function.c (is_numeric): Use it. + + * main.c (struct command_switch): Store the switch char in an + unsigned char to shut up GCC about using it with ctype.h macros. + Besides, it _is_ always unsigned. + +1999-08-24 Paul D. Smith + + * make.texinfo: Change "dependency" to "prerequisite" and + "dependencies" to "prerequisites". Various other cleanups related + to the terminology change. + * file.c: Change debugging and error messages to use + "prerequisite" instead of "dependency". + * implicit.c: Ditto. + * remake.c: Ditto. + * NEWS: Document it. + +1999-08-23 Paul D. Smith + + * remake.c (update_file): Move the considered check into the + double-colon rule loop, so we consider double-colon rules + individually (otherwise after the first is pruned, the rest won't + get run). + + * README.template: Minor changes. + + Remove the debugging features of the jobserver, so it no longer + writes distinct tokens to the pipe. Thus, we don't need to store + the token we get. A side effect of this is to remove a potential + "unavailable token" situation: make-1 invokes make-2 with its + special token and make-3 with a normal token; make-2 completes. + Now we're waiting for make-3 but using 2 tokens; our special token + is idle. In the new version we don't have special tokens per se, + we merely decide if we already have a child or not. If we don't, + we don't need a token. If we do, we have to get one to run the + next child. Similar for putting tokens back: if we're cleaning up + the last child, we don't put a token back. Otherwise, we do. + + * main.c: Add a new, internal flag --jobserver-fds instead of + overloading the meaning of -j. Remove job_slots_str and add the + stringlist jobserver_fds. + (struct command_switch): We don't need the int_string type. + (switches[]): Add a new option for --jobserver-fds and remove + conditions around -j. Make the description for the former 0 so it + doesn't print during "make --help". + (main): Rework jobserver parsing. If we got --jobserver-fds + make sure it's valid. We only get one and job_slots must be 0. + If we're the toplevel make (-jN without --jobserver-fds) create + the pipe and write generic tokens. + Create the stringlist struct for the submakes. + Clean up the stringlist where necessary. + (init_switches): Remove int_string handling. + (print_usage): Don't print internal flags (description ptr is 0). + (decode_switches): Remove int_string handling. + (define_makeflags): Remove int_string handling. + + * job.c: Remove my_job_token flag and all references to the + child->job_token field. + (free_job_token): Remove this and merge it into free_child(). + (reap_children): Rework the "reaped a child" logic slightly. + Don't call defunct free_job_token anymore. Always call + free_child, even if we're dying. + (free_child): If we're not freeing the only child, put a token + back in the pipe. Then, if we're dying, don't bother to free. + (new_job): If we are using the jobserver, loop checking to see if + a) there are no children or b) we get a token from the pipe. + + * job.h (struct child): Remove the job_token field. + +1999-08-20 Paul D. Smith + + * variable.c (try_variable_definition): Allocate for variable + expansion in f_append with a simple variable: if we're looking at + target-specific variables we don't want to trash the buffer. + Noticed by Reiner Beninga . + +1999-08-16 Eli Zaretskii + + * main.c (main) [__MSDOS__]: Mirror any backslashes in argv[0], to + avoid problems in shell commands that use backslashes as escape + characters. + +1999-08-16 Paul D. Smith + + * Version 3.77.93 released. + +1999-08-13 Paul D. Smith + + Another jobserver algorithm change. We conveniently forgot that + the blocking bit is shared by all users of the pipe, it's not a + per-process setting. Since we have many make processes all + sharing the pipe we can't use the blocking bit as a signal handler + flag. Instead, we'll dup the pipe's read FD and have the SIGCHLD + handler close the dup'd FD. This will cause the read() to fail + with EBADF the next time we invoke it, so we know we need to reap + children. We then re-dup and reap. + + * main.c (main): Define the job_rfd variable to hold the dup'd FD. + Actually dup the read side of the pipe. Don't bother setting the + blocking bit on the file descriptor. + * make.h: Declare the job_rfd variable. + * job.c (child_handler): If the dup'd jobserver pipe is open, + close it and assign -1 to job_rfd to notify the main program that + we got a SIGCHLD. + (start_job_command): Close the dup'd FD before exec'ing children. + Since we open and close this thing so often it doesn't seem + worth it to use the close-on-exec bit. + (new_job): Remove code for testing/setting the blocking bit. + Instead of EAGAIN, test for EBADF. If the dup'd FD has been + closed, re-dup it before we reap children. + + * function.c (func_shell): Be a little more accurate about the + length of the error string to allocate. + + * expand.c (variable_expand_for_file): If there's no filenm info + (say, from a builtin command) then reset reading_file to 0. + +1999-08-09 Paul D. Smith + + * maintMakefile: Use g in sed (s///g) to replace >1 variable per + line. + + * Makefile.DOS.template [__MSDOS__]: Fix mostlyclean-aminfo to + remove the right files. + +1999-08-01 Eli Zaretskii + + * function.c (msdos_openpipe) [__MSDOS__]: *Really* return a FILE + ptr. + +1999-08-01 Paul D. Smith + + New jobserver algorithm to avoid a possible hole where we could + miss SIGCHLDs and get into a deadlock. The original algorithm was + suggested by Roland McGrath with a nice refinement by Paul Eggert. + Many thanks as well to Tim Magill and Howard Chu, who also + provided many viable ideas and critiques. We all had a fun week + dreaming up interesting ways to use and abuse UNIX syscalls :). + + Previously we could miss a SIGCHLD if it happened after we reaped + the children but before we re-entered the blocking read. If this + happened to all makes and/or all children, make would never wake + up. + + We avoid this by having the SIGCHLD handler reset the blocking bit + on the jobserver pipe read FD (normally read does block in this + algorithm). Now if the handler is called between the time we reap + and the time we read(), and there are no tokens available, the + read will merely return with EAGAIN instead of blocking. + + * main.c (main): Set the blocking bit explicitly here. + * job.c (child_handler): If we have a jobserver pipe, set the + non-blocking bit for it. + (start_waiting_job): Move the token stuff back to new_job; if we + do it here then we're not controlling the number of remote jobs + started! + (new_job): Move the check for job slots to _after_ we've created a + child structure. If the read returns without getting a token, set + the blocking bit then try to reap_children. + + * make.h (EINTR_SET): Define to test errno if EINTR is available, + or 0 otherwise. Just some code cleanup. + * arscan.c (ar_member_touch): Use it. + * function.c (func_shell): Use it. + * job.c (reap_children): Use it. + * remake.c (touch_file): Use it. + +1999-07-28 Paul D. Smith + + * make.h: Define _() and N_() macros as passthrough to initiate + NLS support. + * : Add _()/N_() around translatable strings. + +1999-07-27 Paul D. Smith + + * read.c: Make sure make.h comes before other headers. + +1999-07-26 Paul D. Smith + + * make.texinfo (Quick Reference): Update with the new features. + +1999-07-25 Eli Zaretskii + + * remake.c [__MSDOS__]: Don't include variables.h, it's already + included. + + * function.c (msdos_openpipe) [__MSDOS__]: Return FILE ptr. + (func_shell) [__MSDOS__]: Fix the argument list. + + * Makefile.DOS.template: Update from Makefile.in. + + * README.DOS.template: Configure command fixed. + + * configh.dos.template: Update to provide definitions for + uintmax_t, fd_set_size_t, and HAVE_SELECT. + +1999-07-24 Paul D. Smith + + * Version 3.77.91 released. + + * configure.in: Changes to the boostrapping code: if build.sh.in + doesn't exist configure spits an error and generates an empty + build.sh file which causes make to be confused. + * maintMakefile: Don't build README early. + +1999-07-23 Paul D. Smith + + * job.c (my_job_token): This variable controls whether we've + handed our personal token to a subprocess or not. Note we could + probably infer this from the value of job_slots_used, but it's + clearer to just keep it separately. Job_slots_used isn't really + relevant when running the job server. + (free_job_token): New function: free a job token. If we don't + have one, no-op. If we have the personal token, reclaim it. If + we have another token, write it back to the pipe. + (reap_children): Call free_job_token. + (free_child): Call free_job_token. + (start_job_command): Remove duplicate test for '+' in the command. + If we don't appear to be running a recursive make, close the + jobserver filedescriptors. + (start_waiting_job): If our personal token is available, use that + instead of going to the server pipe. + (*): Add the token value to many debugging statements, and print + the child target name in addition to the ptr hex value. + Change the default "no token" value from '\0' to '-' so it looks + better in the output. + + * main.c (main): Install the child_handler with sigaction() + instead of signal() if we have it. On SysV systems, signal() uses + SysV semantics which are a pain. But sigaction() always does what + we want. + (main): If we got job server FDs from the environment, test them + to see if they're open. If not, the parent make closed them + because it didn't think we were a submake. Print a warning and + suggestion to use "+" on the submake invocation, and hard-set to + -j1 for this instance of make. + (main): Change the algorithm for assigning slots to be more + robust. Previously make checked to see if it thought a subprocess + was a submake and if so, didn't give it a token. Since make's + don't consume tokens we could spawn many of makes fighting for a + small number of tokens. Plus this is unreliable because submakes + might not be recognized by the parent (see above) then all the + tokens could be used up by unrecognized makes, and no one could + run. Now every make consumes a token from its parent. However, + the make can also use this token to spawn a child. If the make + wants more than one, it goes to the jobserver pipe. Thus there + will never be more than N makes running for -jN, and N*2 processes + (N makes and their N children). Every make can always run at + least one job, and we'll never deadlock. (Note the closing of the + pipe for non-submakes also solves this, but this is still a better + algorithm.) So! Only put N-1 tokens into the pipe, since the + topmost make keeps one for itself. + + * configure.in: Find sigaction. Disable job server support unless + the system provides it, in addition to either waitpid() or + wait3(). + +1999-07-22 Rob Tulloh + + * arscan.c (ar_member_touch) [WINDOWS32]: The ar_date field is a + string on Windows, not a timestamp. + +1999-07-21 Paul D. Smith + + * Version 3.77.90 released. + + * Makefile.am (AUTOMAKE_OPTIONS): Require automake 1.4. + + * function.c: Rearrange so we don't need to predeclare the + function_table array; K&R C compilers don't like that. + + * acinclude.m4 (AC_FUNC_SELECT): Ouch; this requires an ANSI C + compiler! Change to work with K&R compilers as well. + + * configure.in (AC_OUTPUT): Put build.sh back. I don't know how I + thought it would work this way :-/. We'll have to think of + something else. + * Makefile.am: Remove rule to create build.sh. + + * default.c (default_suffix_rules): Rearrange the default command + lines to conform to POSIX rules (put the filename argument $< + _after_ the OUTPUT_OPTION, not before it). + + * various: Changed !strncmp() calls to strneq() macros. + + * misc.c (sindex): Make slightly more efficient. + + * dir.c (file_impossible): Change savestring(X,strlen(X)) to xstrdup(). + * implicit.c (pattern_search): Ditto. + * main.c (enter_command_line_file): Ditto. + (main): Ditto. + * misc.c (copy_dep_chain): Ditto. + * read.c (read_makefile): Ditto. + (parse_file_seq): Ditto. + (tilde_expand): Ditto. + (multi_glob): Ditto. + * rule.c (install_pattern_rule): Ditto. + * variable.c (define_variable_in_set): Ditto. + (define_automatic_variables): Ditto. + * vpath.c (construct_vpath_list): Ditto. + + * misc.c (xrealloc): Some reallocs are non-standard: work around + them in xrealloc by calling malloc if PTR is NULL. + * main.c (main): Call xrealloc() directly instead of testing for + NULL. + + * function.c (func_sort): Don't try to free NULL; some older, + non-standard versions of free() don't like it. + + * configure.in (--enable-dmalloc): Install some support for using + dmalloc (http://www.dmalloc.com/) with make. Use --enable-dmalloc + with configure to enable it. + + * function.c (function_table_entry): Whoops! The function.c + rewrite breaks backward compatibility: all text to a function is + broken into arguments, and extras are ignored. So $(sort a,b,c) + returns "a"! Etc. Ouch. Fix it by making a positive value in + the REQUIRED_ARGS field mean exactly that many arguments to the + function; any "extras" are considered part of the last argument as + before. A negative value means at least that many, but may be + more: in this case all text is broken on commas. + (handle_function): Stop when we've seen REQUIRED_ARGS args, if >0. + (expand_builtin_function): Compare number of args to the absolute + value of REQUIRED_ARGS. + +1999-07-20 Paul D. Smith + + * job.c (start_job_command): Ensure that the state of the target + is cs_running. It might not be if we skipped all the lines due to + -n (for example). + + * commands.c (execute_file_commands): If we discover that the + command script is empty and succeed early, set cs_running so the + modtime of the target is still rechecked. + + * rule.c (freerule): Free the dependency list for the rule. + + * implicit.c (pattern_search): When turning an intermediate file + into a real target, keep the also_make list. + Free the dep->name if we didn't use it during enter_file(). + +1999-07-16 Paul D. Smith + + * read.c (read_makefile): Don't allocate the commands buffer until + we're sure we found a makefile and won't return early (mem leak). + + * job.c (start_job_command): Broken #ifdef test: look for F_SETFD, + not FD_SETFD. Close-on-exec isn't getting set on the bad_stdin + file descriptor and it's leaking :-/. + * getloadavg.c (getloadavg): Ditto. + +1999-07-15 Paul D. Smith + + * read.c (read_makefile): Fix some potential memory stomps parsing + `define' directives where no variable name is given. + + * function.c (func_call): Rename from func_apply. Various code + cleanup and tightening. + (function_table): Add "call" as a valid builtin function. + + * make.texinfo (Call Function): Document it. + + * NEWS: Announce it. + +1999-07-09 Eli Zaretskii + + * variable.c (try_variable_definition) [__MSDOS__, WINDOWS32]: + Treat "override SHELL=" the same as just "SHELL=". + +1999-07-09 Paul D. Smith + + * job.c (start_waiting_job): Don't get a second job token if we + already have one; if we're waiting on the load to go down + start_waiting_job() might get called twice on the same file. + + * filedef.h (struct file): Add new field, mtime_before_update. + When notice_finished_file runs it assigns the cached last_mtime to + this field. + * remake.c (update_goal_chain): Notice that a file wasn't updated + by asking if it changed (g->changed) and comparing the current + cached time (last_mtime) with the previous one, stored in + mtime_before_update. The previous check ("did last_mtime changed + during the run of update_file?") fails for parallel builds because + last_mtime is set during reap_children, before update_file is run. + This causes update_goal_chain to always return -1 (nothing + rebuilt) when running parallel (-jN). This is OK during "normal" + builds since our caller (main) treats these cases identically in + that case, but if when rebuilding makefiles the difference is very + important, as it controls whether we re-exec or not. + * file.c (file_hash_enter): Copy the mtime_before_update field. + (snap_deps): Initialize mtime_before_update to -1. + * main.c (main): Initialize mtime_before_update on old (-o) and + new (-W) files. + +1999-07-08 Paul D. Smith + + * main.c (switches): Define a new switch -R (or + --no-builtin-variables). This option disables the defining of all + the GNU make builtin variables. + (main): If -R was given, force -r as well. + * default.c (define_default_variables): Test the new flag. + * make.h: Declare global flag. + * make.texinfo (Options Summary): Document the new option. + (Implicit Variables): Ditto. + +1999-07-06 Paul D. Smith + + * make.texinfo (Options Summary): Correct examples in + --print-data-base option summary (problem reported by David Morse + ). + + * arscan.c: Add support for archives in Windows (VC++). Frank + Libbrecht provided info on how to do + this. + * NMakefile.template (CFLAGS_any): Remove NO_ARCHIVES from the + compile line. + * build_w32.bat: Ditto. + + * remake.c (no_rule_error): Fix -include/sinclude so it doesn't + give errors if you try to -include the same file twice. + (updating_makefiles): New variable: we need to know this info in + no_rule_error() so we know whether to print an error or not. + (update_file_1): Unconditionally call no_rule_error(), don't try + to play games with the dontcare flag. + +1999-06-14 Paul D. Smith + + * make.texinfo (Remaking Makefiles): Add a description of how to + prevent implicit rule searches for makefiles. + + * make.1: Remove statement that make continues processing when -v + is given. + +1999-06-14 Paul D. Smith + + * read.c (read_makefile): Cast -1 arguments to + variable_expand_string() to long. Alexandre Sauve + reports that without casts, this breaks + on a NEC SUPER-UX SX-4 system (and it's wrong without a cast + anyway). Of course, (a) I'd really love to start using function + prototypes, and (b) there's a whole slew of issues related to int + vs. long and signed vs. unsigned in the length handling of + variable buffers, etc. Gross. Needs a complete mucking-out. + * expand.c (variable_expand): Ditto. + + * acinclude.m4 (AC_FUNC_SELECT): Slight enhancement for AIX 3.2 by + Lars Hecking . + + * read.c (get_next_mword): Allow colons to be escaped in target + names: fix for regression failure. + +1999-04-26 Paul D. Smith + + * main.c (main): Reset read_makefiles to empty after processing so + we get the right error message. + +1999-04-25 Paul D. Smith + + * make.texinfo: Updates to @dircategory and @direntry suggested by + Karl Berry . + +1999-04-23 Eli Zaretskii + + * job.c (start_job_command) [__MSDOS__]: Call unblock_sigs before + turning off dos_command_running, so child's signals produce the + right effect. + + * commands.c (fatal_error_signal) [__MSDOS__]: Use EXIT_FAILURE + instead of 1. + +1999-04-18 Eli Zaretskii + + * configh.dos.template: Update to recognize that version 2.02 of + DJGPP contains sys_siglist stuff. + +1999-04-14 Paul D. Smith + + * make.texinfo (Options/Recursion): Document the job server. + (Parallel): Tweaks. + +1999-04-13 Paul D. Smith + + Implement a new "job server" feature; the implementation was + suggested by Howard Chu . + + * configure.in (job-server): New disable option for job server + support--it's enabled by default. If it works well this will go + away. + + * NEWS: Summarize the new feature. + + * acconfig.h: New definition MAKE_JOBSERVER if job server support + is enabled. + * config.h-vms.template: Undef MAKE_JOBSERVER for this port. + * config.h.W32.template: Ditto. + * config.ami.template: Ditto. + + * main.c (struct command_switch): Add a new type: int_string. + (switches[]) Use int_string for -j if MAKE_JOBSERVER. + (init_switches): Initialize the new int_string switch type. + (print_usage): New function, extracted from decode_switches(). + (decode_switches): Call it. Decode the new int_string switch type. + (define_makeflags): Add new int_string switch data to MAKEFLAGS. + (job_fds[]) Array to contain the pipe file descriptors. + (main): Parse the job_slots_str option results. If necessary, + create the pipe and seed it with tokens. Set the non-blocking bit + for the read fd. Enable the signal handler for SIGCHLD even if we + have a non-hanging wait; it's needed to interrupt the select() in + job.c:start_waiting_job(). + + * make.h: Declare job_fds[]. + + * job.h (struct child): Add job_token field to store the token for + this job (if any). + + * job.c (reap_children): When a child is fully reaped, release the + token back into the pipe. + (free_child): If the child to be freed still has a token, put it + back. + (new_job): Initialize the job_token member. + (start_waiting_job): For local jobs, if we're using the pipe, get + a token before we check the load, etc. We do this by performing a + non-blocking read in a loop. If the read fails, no token is + available. Do a select on the fd to wait for a token. We need to + re-enable the signal handler for SIGCHLD even if we have a + non-hanging waitpid() or wait3(), so that the signal will + interrupt the select() and we can wake up to reap children. + (child_handler): Re-enable the signal handler. The count is still + kept although it's not needed or used unless you don't have + waitpid() or wait3(). + +1999-04-10 Paul D. Smith + + * main.c (main): Reset the considered bit on all the makefiles if + something failed to update; we need to examine them again if they + appear as normal targets in order to get the proper error message. + +1999-04-09 Paul D. Smith + + Performance enhancement from Tim Magill . + + * remake.c (update_file): If you have large numbers of + dependencies and you run in parallel, make can spend considerable + time each pass through the graph looking at branches it has + already seen. Since we only reap_children() when starting a pass, + not in the middle, if a branch has been seen already in that pass + nothing interesting can happen until the next pass. So, we toggle + a bit saying whether we've seen this target in this pass or not. + (update_goal_chain): Initially set the global considered toggle to + 1, since all targets initialize their boolean to 0. At the end of + each pass, toggle the global considered variable. + * filedef.h (struct file): Per-file considered toggle bit. + * file.c: New global toggle variable considered. + +1999-04-05 Paul D. Smith + + * arscan.c (ar_scan): Added support for ARFZMAG (compressed + archives?) for Digital UNIX C++. Information provided by + Patrick E. Krogel . + (ar_member_touch): Ditto. + +1999-04-03 Paul D. Smith + + * remake.c (f_mtime): If: a) we found a file and b) we didn't + create it and c) it's not marked as an implicit target and d) it + is marked as an intermediate target, then it was so marked due to + an .INTERMEDIATE special target, but it already existed in the + directory. In this case, unset the intermediate flag so we won't + delete it when make is done. It feels like it would be cleaner to + put this check in update_file_1() but I worry it'll get missed... + +1999-04-01 Paul D. Smith + + * job.c (construct_command_argv_internal): Use bcopy() to copy + overlapping strings, rather than strcpy(). ISO C says the latter + is undefined. Found this in a bug report from 1996! Ouch! + +1999-03-31 Paul D. Smith + + * read.c (readline): Ignore carriage returns at the end of the + line, to allow Windows-y CRLF line terminators. + +1999-03-30 Paul D. Smith + + * configure.in: Don't put build.sh here, since build.sh.in doesn't + exist initially. This cause autoreconf and automake to fail when + run on a clean CVS checkout. Instead, we create build.sh in the + Makefile (see below). + + * Makefile.am: Remove BUILT_SOURCES; this is no longer relevant. + Put those files directly into EXTRA_DIST so they're distributed. + Create a local build rule to create build.sh. + Create a local maintainer-clean rule to delete all the funky + maintainers files. + + * maintMakefile: Makefile.in depends on README, since automake + fails if it doesn't exist. Also don't remove glob/Makefile.in + here, as it causes problems. + +1999-03-26 Paul D. Smith + + * configure.in: Substitute GLOBLIB if we need the link the + glob/libglob.a library. + * Makefile.am (make_LDADD): Use the subst variable GLOBLIB so we + don't link the local libglob.a at all if we don't need it. + * build.template: Don't compile glob/*.o unless we want globlib. + * maintMakefile (build.sh.in): Substitute the glob/*.o files + separately. + +1999-03-25 Paul D. Smith + + * make.texinfo: Various typos and additions, pointed out by James + G. Sack . + +1999-03-22 Paul D. Smith + + * make.texinfo (Functions): Add a new section documenting the new + $(error ...) and $(warning ...) functions. Also updated copyright + dates. + * NEWS: Updated for the new functions. + * function.c (func_error): Implement the new $(error ...) and + $(warning ...) functions. + (function_table): Insert new functions into the table. + (func_firstword): Don't call find_next_token() with argv[0] + itself, since that function modifies the pointer. + * function.c: Cleanups and slight changes to the new method of + calling functions. + +1999-03-20 Han-Wen Nienhuys + + * function.c: Rewrite to use one C function per make function, + instead of a huge switch statement. Also allows some cleanup of + multi-architecture issues, and a cleaner API which makes things + like func_apply() simple. + + * function.c (func_apply): Initial implementation. Expand either + a builtin function or a make variable in the context of some + arguments, provided as $1, $2, ... $N. + +1999-03-19 Eli Zaretskii +1999-03-19 Rob Tulloh + + * job.c (construct_command_argv_internal): Don't treat _all_ + backslashes as escapes, only those which really escape a special + character. This allows most normal "\" directory separators to be + treated normally. + +1999-03-05 Paul D. Smith + + * configure.in: Check for a system strdup(). + * misc.c (xstrdup): Created. Suggestion by Han-Wen Nienhuys + . + * make.h: Prototype xstrdup(). + * remake.c (library_search): Use it. + * main.c (main): Use it. + (find_and_set_default_shell): Use it. + * job.c (construct_command_argv_internal): Use it. + * dir.c (find_directory): Use it. + + * Makefile.am, configure.in: Use AC_SUBST_FILE to insert the + maintMakefile instead of "include", to avoid automake 1.4 + incompatibility. + +1999-03-04 Paul D. Smith + + * amiga.c, amiga.h, ar.c, arscan.c, commands.c, commands.h, + * default.c, dep.h, dir.c, expand.c, file.c, filedef.h, function.c, + * implicit.c, job.c, job.h, main.c, make.h, misc.c, read.c, remake.c + * remote-cstms.c, remote-stub.c, rule.h, variable.c, variable.h, + * vpath.c, Makefile.ami, NMakefile.template, build.template, + * makefile.vms: Updated FSF address in the copyright notice. + + * variable.c (try_variable_definition): If we see a conditional + variable and we decide to set it, re-type it as recursive so it + will be expanded properly later. + +1999-02-22 Paul D. Smith + + * NEWS: Mention new .LIBPATTERNS feature. + + * make.texinfo (Libraries/Search): Describe the use and + ramifications of the new .LIBPATTERNS variable. + + * remake.c (library_search): Instead of searching only for the + hardcoded expansion "libX.a" for a library reference "-lX", we + obtain a list of patterns from the .LIBPATTERNS variable and + search those in order. + + * default.c: Added a new default variable .LIBPATTERNS. The + default for UNIX is "lib%.so lib%.a". Amiga and DOS values are + also provided. + + * read.c: Remove bogus HAVE_GLOB_H references; always include + vanilla glob.h. + +1999-02-21 Paul D. Smith + + * function.c (expand_function): Set value to 0 to avoid freeing it. + * variable.c (pop_variable_scope): Free the value of the variable. + (try_variable_definition): For simple variables, use + allocated_variable_expand() to avoid stomping on the variable + buffer when we still need it for other things. + + * arscan.c: Modified to support AIX 4.3 big archives. The changes + are based on information provided by Phil Adams + . + +1999-02-19 Paul D. Smith + + * configure.in: Check to see if the GNU glob library is already + installed on the system. If so, _don't_ add -I./glob to the + compile line. Using the system glob code with the local headers + is very bad mojo! + Rewrite SCCS macros to use more autoconf facilities. + + * Makefile.am: Move -Iglob out of INCLUDES; it'll get added to + CPPFLAGS by configure now. + Automake 1.4 introduced its own "include" feature which conflicts + with the maintMakefile stuff. A hack that seems to work is add a + space before the include :-/. + + * build.template: Move -Iglob out of the compile line; it'll get + added to CPPFLAGS by configure now. + +1999-02-16 Glenn D. Wolf + + * arscan.c (ar_scan) [VMS]: Initialized VMS_member_date before + calling lbr$get_index since if the archive is empty, + VMS_get_member_info won't get called at all, and any leftover date + will be used. This bug shows up if any member of any archive is + made, followed by a dependency check on a different, empty + archive. + +1998-12-13 Martin Zinser + + * config.h-vms [VMS]: Set _POSIX_C_SOURCE. Redefine the getopt + functions so we don't use the broken VMS versions. + * makefile.com [VMS]: Allow debugging. + * dir.c (dir_setup_glob) [VMS]: Don't extern stat() on VMS. + +1998-11-30 Paul D. Smith + + * signame.c (init_sig): Check the sizes of signals being set up to + avoid array overwrites (if the system headers have problems). + +1998-11-17 Paul D. Smith + + * read.c (record_files): Clean up some indentation. + +1998-11-08 Han-Wen Nienhuys + + * rule.c (print_rule_data_base): Fix arguments to fatal() call. + +1998-10-13 Paul D. Smith + + * job.c (start_job_command): If the command list resolves to no + chars at all (e.g.: "foo:;$(empty)") then command_ptr is NULL; + quit early. + +1998-10-12 Andreas Schwab + + * rule.c (print_rule_data_base): Ignore num_pattern_rules if it is + zero. + +1998-10-09 Paul D. Smith + + * read.c (read_makefile): Allow non-empty lines to expand to the + empty string after variable, etc., expansion, and be ignored. + +1998-09-21 Paul D. Smith + + * job.c (construct_command_argv_internal): Only add COMMAND.COM + "@echo off" line for non-UNIXy shells. + +1998-09-09 Paul D. Smith + + * w32/subproc/sub_proc.c: Add in missing HAVE_MKS_SHELL tests. + +1998-09-04 Paul D. Smith + + * read.c (read_makefile): If we hit the "missing separator" error, + check for the common case of 8 spaces instead of a TAB and give an + extra comment to help people out. + +1998-08-29 Paul Eggert + + * configure.in (AC_STRUCT_ST_MTIM_NSEC): + Renamed from AC_STRUCT_ST_MTIM. + + * acinclude.m4 (AC_STRUCT_ST_MTIM_NSEC): Likewise. + Port to UnixWare 2.1.2 and pedantic Solaris 2.6. + + * acconfig.h (ST_MTIM_NSEC): + Renamed from HAVE_ST_MTIM, with a new meaning. + + * filedef.h (FILE_TIMESTAMP_FROM_S_AND_NS): + Use new ST_MTIM_NSEC macro. + +1998-08-26 Paul D. Smith + + * remake.c (check_dep): For any intermediate file, not just + secondary ones, try implicit and default rules if no explicit + rules are given. I'm not sure why this was restricted to + secondary rules in the first place. + +1998-08-24 Paul D. Smith + + * make.texinfo (Special Targets): Update documentation for + .INTERMEDIATE: if used with no dependencies, then it does nothing; + old docs said it marked all targets as intermediate, which it + didn't... and which would be silly :). + + * implicit.c (pattern_search): If we find a dependency in our + internal tables, make sure it's not marked intermediate before + accepting it as a found_file[]. + +1998-08-20 Paul D. Smith + + * ar.c (ar_glob): Use existing alpha_compare() with qsort. + (ar_glob_alphacompare): Remove it. + + Modify Paul Eggert's patch so we don't abandon older systems: + + * configure.in: Warn the user if neither waitpid() nor wait3() is + available. + + * job.c (WAIT_NOHANG): Don't syntax error on ancient hosts. + (child_handler, dead_children): Define these if WAIT_NOHANG is not + available. + (reap_children): Only track the dead_children count if no + WAIT_NOHANG. Otherwise, it's a boolean. + + * main.c (main): Add back signal handler if no WAIT_NOHANG is + available; only use default signal handler if it is. + +1998-08-20 Paul Eggert + + Install a more robust signal handling mechanism for systems which + support it. + + * job.c (WAIT_NOHANG): Define to a syntax error if our host + is truly ancient; this should never happen. + (child_handler, dead_children): Remove. + (reap_children): Don't try to keep separate track of how many + dead children we have, as this is too bug-prone. + Just ask the OS instead. + (vmsHandleChildTerm): Fix typo in error message; don't mention + child_handler. + + * main.c (main): Make sure we're not ignoring SIGCHLD/SIGCLD; + do this early, before we could possibly create a subprocess. + Just use the default behavior; don't have our own handler. + +1998-08-18 Eli Zaretskii + + * read.c (read_makefile) [__MSDOS__, WINDOWS32]: Add code to + recognize library archive members when dealing with drive spec + mess. Discovery and initial fix by George Racz . + +1998-08-18 Paul D. Smith + + * configure.in: Check for stdlib.h explicitly (some hosts have it + but don't have STDC_HEADERS). + * make.h: Use HAVE_STDLIB_H. Clean up some #defines. + * config.ami: Re-compute based on new config.h.in contents. + * config.h-vms: Ditto. + * config.h.W32: Ditto. + * configh.dos: Ditto. + + * dir.c (find_directory) [WINDOWS32]: Windows stat() fails if + directory names end with `\' so strip it. + +1998-08-17 Paul D. Smith + + * make.texinfo: Added copyright year to the printed copy. Removed + the price from the manual. Change the top-level reference to + running make to be "Invoking make" instead of "make Invocation", + to comply with GNU doc standards. + + * make.h (__format__, __printf__): Added support for these in + __attribute__ macro. + (message, error, fatal): Use ... prototype form under __STDC__. + Add __format__ attributes for printf-style functions. + + * configure.in (AC_FUNC_VPRINTF): Check for vprintf()/_doprnt(). + + * misc.c (message, error, fatal): Add preprocessor stuff to enable + creation of variable-argument functions with appropriate + prototypes, that works with ANSI, pre-ANSI, varargs.h, stdarg.h, + v*printf(), _doprnt(), or none of the above. Culled from GNU + fileutils and slightly modified. + (makefile_error, makefile_error): Removed (merged into error() and + fatal(), respectively). + * amiga.c: Use them. + * ar.c: Use them. + * arscan.c: Use them. + * commands.c: Use them. + * expand.c: Use them. + * file.c: Use them. + * function.c: Use them. + * job.c: Use them. + * main.c: Use them. + * misc.c: Use them. + * read.c: Use them. + * remake.c: Use them. + * remote-cstms.c: Use them. + * rule.c: Use them. + * variable.c: Use them. + + * make.h (struct floc): New structure to store file location + information. + * commands.h (struct commands): Use it. + * variable.c (try_variable_definition): Use it. + * commands.c: Use it. + * default.c: Use it. + * file.c: Use it. + * function.c: Use it. + * misc.c: Use it. + * read.c: Use it. + * rule.c: Use it. + +1998-08-16 Paul Eggert + + * filedef.h (FILE_TIMESTAMP_PRINT_LEN_BOUND): Add 10, for nanoseconds. + +1998-08-16 Paul Eggert + + * filedef.h (FLOOR_LOG2_SECONDS_PER_YEAR): New macro. + (FILE_TIMESTAMP_PRINT_LEN_BOUND): Tighten bound, and try to + make it easier to understand. + +1998-08-14 Paul D. Smith + + * read.c (read_makefile): We've already unquoted any colon chars + by the time we're done reading the targets, so arrange for + parse_file_seq() on the target list to not do so again. + +1998-08-05 Paul D. Smith + + * configure.in: Added glob/configure.in data. We'll have the glob + code include the regular make config.h, rather than creating its + own. + + * getloadavg.c (main): Change return type to int. + +1998-08-01 Paul Eggert + + * job.c (reap_children): Ignore unknown children. + +1998-07-31 Paul D. Smith + + * make.h, filedef.h, dep.h, rule.h, commands.h, remake.c: + Add prototypes for functions. Some prototypes needed to be moved + in order to get #include order reasonable. + +1998-07-30 Paul D. Smith + + * make.h: Added MIN/MAX. + * filedef.h: Use them; remove FILE_TIMESTAMP_MIN. + +1998-07-30 Paul Eggert + + Add support for sub-second timestamp resolution on hosts that + support it (just Solaris 2.6, so far). + + * acconfig.h (HAVE_ST_MTIM, uintmax_t): New undefs. + * acinclude.m4 (jm_AC_HEADER_INTTYPES_H, AC_STRUCT_ST_MTIM, + jm_AC_TYPE_UINTMAX_T): New defuns. + * commands.c (delete_target): Convert file timestamp to + seconds before comparing to archive timestamp. Extract mod + time from struct stat using FILE_TIMESTAMP_STAT_MODTIME. + * configure.in (C_STRUCT_ST_MTIM, jm_AC_TYPE_UINTMAX_T): Add. + (AC_CHECK_LIB, AC_CHECK_FUNCS): Add clock_gettime. + * file.c (snap_deps): Use FILE_TIMESTAMP, not time_t. + (file_timestamp_now, file_timestamp_sprintf): New functions. + (print_file): Print file timestamps as FILE_TIMESTAMP, not + time_t. + * filedef.h: Include if available and if HAVE_ST_MTIM. + (FILE_TIMESTAMP, FILE_TIMESTAMP_STAT_MODTIME, FILE_TIMESTAMP_MIN, + FILE_TIMESTAMPS_PER_S, FILE_TIMESTAMP_FROM_S_AND_NS, + FILE_TIMESTAMP_DIV, FILE_TIMESTAMP_MOD, FILE_TIMESTAMP_S, + FILE_TIMESTAMP_NS, FILE_TIMESTAMP_PRINT_LEN_BOUND): New macros. + (file_timestamp_now, file_timestamp_sprintf): New decls. + (struct file.last_mtime, f_mtime, file_mtime_1, NEW_MTIME): + time_t -> FILE_TIMESTAMP. + * implicit.c (pattern_search): Likewise. + * vpath.c (vpath_search, selective_vpath_search): Likewise. + * main.c (main): Likewise. + * remake.c (check_dep, name_mtime, library_search, f_mtime): Likewise. + (f_mtime): Use file_timestamp_now instead of `time'. + Print file timestamp with file_timestamp_sprintf. + * vpath.c (selective_vpath_search): Extract file time stamp from + struct stat with FILE_TIMESTAMP_STAT_MODTIME. + +1998-07-28 Paul D. Smith + + * Version 3.77 released. + + * dosbuild.bat: Change to DOS CRLF line terminators. + + * make-stds.texi: Update from latest version. + + * make.texinfo (Options Summary): Clarify that the -r option + affects only rules, not builtin variables. + +1998-07-27 Paul D. Smith + + * make.h: Make __attribute__ resolve to empty for non-GCC _and_ + for GCC pre-2.5.x. + + * misc.c (log_access): Print UID/GID's as unsigned long int for + maximum portability. + + * job.c (reap_children): Print PIDs as long int for maximum + portability. + +1998-07-24 Eli Zaretskii + + * Makefile.DOS (*_INSTALL, *_UNINSTALL): Replace `true' with `:'. + +1998-07-25 Paul D. Smith + + * Version 3.76.94 released. + +1998-07-23 Paul D. Smith + + * config.h.W32.template: Make sure all the #defines of macros here + have a value (e.g., use ``#define HAVE_STRING_H 1'' instead of + just ``#define HAVE_STRING_H''. Keeps the preprocessor happy in + some contexts. + + * make.h: Remove __attribute__((format...)) stuff; using it with + un-prototyped functions causes older GCC's to fail. + + * Version 3.76.93 released. + +1998-07-22 Paul D. Smith + + * file.c (print_file_data_base): Fix average calculation. + +1998-07-20 Paul D. Smith + + * main.c (die): Postpone the chdir() until after + remove_intermediates() so that intermediate targets with relative + pathnames are removed properly. + +1998-07-17 Paul D. Smith + + * filedef.h (struct file): New flag: did we print an error or not? + + * remake.c (no_rule_error): New function to print error messages, + extraced from remake_file(). + + * remake.c (remake_file): Invoke the new error print function. + (update_file_1): Invoke the error print function if we see that we + already tried this target and it failed, but that an error wasn't + printed for it. This can happen if a file is included with + -include or sinclude and couldn't be built, then later is also + the dependency of another target. Without this change, make just + silently stops :-/. + +1998-07-16 Paul D. Smith + + * make.texinfo: Removed "beta" version designator. + Updated ISBN for the next printing. + +1998-07-13 Paul Eggert + + * acinclude.m4: New AC_LFS macro to determine if special compiler + flags are needed to allow access to large files (e.g., Solaris 2.6). + * configure.in: Invoke it. + +1998-07-08 Eli Zaretskii + + * Makefile.DOS: track changes in Makefile.in. + +1998-07-07 Paul D. Smith + + * remote-cstms.c (start_remote_job): Move gethostbyaddr() to the + top so host is initialized early enough. + + * acinclude.m4: New file. Need some special autoconf macros to + check for network libraries (-lsocket, -lnsl, etc.) when + configuring Customs. + + * configure.in (make_try_customs): Invoke new network libs macro. + +1998-07-06 Paul D. Smith + + * Version 3.76.92 released. + + * README.customs: Added to the distribution. + + * configure.in (make_try_customs): Rewrite to require an installed + Customs library, rather than looking at the build directory. + + * Makefile.am (man_MANS): Install make.1. + * make.1: Renamed from make.man. + + * make.texinfo (Bugs): New mailing list address for GNU make bug + reports. + +1998-07-02 Paul D. Smith + + * Version 3.76.91 released. + + * default.c: Added default rule for new-style RCS master file + storage; ``% :: RCS/%''. + Added default rules for DOS-style C++ files with suffix ".cpp". + They use the new LINK.cpp and COMPILE.cpp macros, which are set by + default to be equal to LINK.cc and COMPILE.cc. + +1998-06-19 Eli Zaretskii + + * job.c (start_job_command): Reset execute_by_shell after an empty + command was skipped. + +1998-06-09 Paul D. Smith + + * main.c (main): Keep track of the temporary filename created when + reading a makefile from stdin (-f-) and attempt to remove it + as soon as we know we're not going to re-exec. If we are, add it + to the exec'd make's cmd line with "-o" so the exec'd make doesn't + try to rebuild it. We still have a hole: if make re-execs then + the temporary file will never be removed. To fix this we'd need + a brand new option that meant "really delete this". + * AUTHORS, getopt.c, getopt1.c, getopt.h, main.c (print_version): + Updated mailing addresses. + +1998-06-08 Paul D. Smith + + * main.c (main): Andreas Luik points out that the + check for makefile :: rules with commands but no dependencies + causing a loop terminates incorrectly. + + * maintMakefile: Make a template for README.DOS to update version + numbers. + +1998-05-30 Andreas Schwab + + * remake.c (update_file_1): Don't free the memory for the + dependency structure when dropping a circular dependency. + +1998-05-30 Eli Zaretskii + + * dir.c (file_exists_p, file_impossible_p, file_impossible) + [__MSDOS__, WINDOWS32]: Retain trailing slash in "d:/", and make + dirname of "d:foo" be "d:". + +1998-05-26 Andreas Schwab + + * read.c (read_makefile): Avoid running past EOS when scanning + file name after `include'. + +1998-05-26 Andreas Schwab + + * make.texinfo (Flavors): Correct description of conditional + assignment, which is not equivalent to ifndef. + (Setting): Likewise. + +1998-05-24 Paul D. Smith + + * arscan.c (ar_name_equal): strncmp() might be implemented as a + macro, so don't put preprocessor conditions inside the arguments + list. + +1998-05-23 Eli Zaretskii + + * read.c (read_makefile) [__MSDOS__, WINDOWS32]: Skip colons in + drive specs when parsing targets, target-specific variables and + static pattern rules. A colon can only be part of drive spec if + it is after the first letter in a token. + +1998-05-22 Eli Zaretskii + + * remake.c (f_mtime) [__MSDOS__]: Allow up to 3 sec of skew before + yelling bloody murder. + + * dosbuild.bat: Use -DINCLUDEDIR= and -DLIBDIR= where appropriate. + + * read.c (parse_file_seq): Combine the special file-handling code + for WINDOWS32 and __MSDOS__ into a single snippet. + (get_next_mword) [__MSDOS__, WINDOWS32]: Allow a word to include a + colon as part of a drive spec. + + * job.c (batch_mode_shell) [__MSDOS__]: Declare. + +1998-05-20 Paul D. Smith + + * Version 3.76.90 released. + +1998-05-19 Paul D. Smith + + * make.texinfo (Make Errors): Added a new appendix describing + common errors make might generate and how to resolve them (or at + least more information on what they mean). + + * maintMakefile (NMAKEFILES): Use the new automake 1.3 feature + to create a dependency file to construct Makefile.DOS, SMakefile, + and NMakefile. + (.dep_segment): Generate the dependency fragment file. + +1998-05-14 Paul D. Smith + + * make.man: Minor changes. + +1998-05-13 Paul D. Smith + + * function.c (pattern_matches,expand_function): Change variables + and types named "word" to something else, to avoid compilation + problems on Cray C90 Unicos. + * variable.h: Modify the function prototype. + +1998-05-11 Rob Tulloh + + * job.c (construct_command_argv_internal) [WINDOWS32]: Turn off + echo when using a batch file, and make sure the command ends in a + newline. + +1998-05-03 Paul D. Smith + + * configure.in (make_try_customs): Add some customs flags if the + user configures custom support. + + * job.c, remote-cstms.c: Merge in changes for custom library. + + * remote-stub.c: Add option to stub start_remote_job_p(). + +1998-05-01 Paul D. Smith + + * remake.c (f_mtime): Install VPATH+ handling for archives; use + the hname field instead of the name field, and rehash when + appropriate. + +1998-04-30 Paul D. Smith + + * rule.c (print_rule_data_base): Print out any pattern-specific + variable values into the rules database. + + * variable.c (print_variable_set): Make this variable extern, to + be called by print_rule_data_base() for pattern-specific variables. + + * make.texinfo (Pattern-specific): Document pattern-specific + variables. + +1998-04-29 Paul D. Smith + + * expand.c (variable_expand_for_file): Make static; its only + called internally. Look up this target in the list of + pattern-specific variables and insert the variable set into the + queue to be searched. + + * filedef.h (struct file): Add a new field to hold the + previously-found pattern-specific variable reference. Add a new + flag to remember whether we already searched for this file. + + * rule.h (struct pattern_var): New structure for storing + pattern-specific variable values. Define new function prototypes. + + * rule.c: New variables pattern_vars and last_pattern_var for + storage and handling of pattern-specific variable values. + (create_pattern_var): Create a new pattern-specific variable value + structure. + (lookup_pattern_var): Try to match a target to one of the + pattern-specific variable values. + +1998-04-22 Paul D. Smith + + * make.texinfo (Target-specific): Document target-specific + variables. + +1998-04-21 Paul D. Smith + + * variable.c (define_variable_in_set): Made globally visible. + (lookup_variable_in_set): New function: like lookup_variable but + look only in a specific variable set. + (target_environment): Use lookup_variable_in_set() to get the + correct export rules for a target-specific variable. + (create_new_variable_set): Create a new variable set, and just + return it without installing it anywhere. + (push_new_variable_scope): Reimplement in terms of + create_new_variable_set. + + * read.c (record_target_var): Like record_files, but instead of + files create a target-specific variable value for each of the + listed targets. Invoked from read_makefile() when the target line + turns out to be a target-specific variable assignment. + +1998-04-19 Paul D. Smith + + * read.c (read_makefile): Rewrite the entire target parsing + section to implement target-specific variables. In particular, we + cannot expand the entire line as soon as it's read in, since we + may want to evaluate parts of it with different variable contexts + active. Instead, start expanding from the beginning until we find + the `:' (or `::'), then determine what kind of line this is and + continue appropriately. + + * read.c (get_next_mword): New function to parse a makefile line + by "words", considering an entire variable or function as one + word. Return the type read in, along with its starting position + and length. + (enum make_word_type): The types of words that are recognized by + get_next_mword(). + + * variable.h (struct variable): Add a flag to specify a per-target + variable. + + * expand.c: Make variable_buffer global. We need this during the + new parsing of the makefile. + (variable_expand_string): New function. Like variable_expand(), + but start at a specific point in the buffer, not the beginning. + (variable_expand): Rewrite to simply call variable_expand_string(). + +1998-04-13 Paul D. Smith + + * remake.c (update_goal_chain): Allow the rebuilding makefiles + step to use parallel jobs. Not sure why this was disabled: + hopefully we won't find out :-/. + +1998-04-11 Paul D. Smith + + * main.c (main): Set the CURDIR makefile variable. + * make.texinfo (Recursion): Document it. + +1998-03-17 Paul D. Smith + + * misc.c (makefile_fatal): If FILE is nil, invoke plain fatal(). + * variable.c (try_variable_definition): Use new feature. + +1998-03-10 Paul D. Smith + + * main.c (main): Don't pass included, rebuilt makefiles to + re-exec'd makes with -o. Reopens a possible loop, but it caused + too many problems. + +1998-03-02 Paul D. Smith + + * variable.c (try_variable_definition): Implement ?=. + * make.texinfo (Setting): Document it. + +1998-02-28 Eli Zaretskii + + * job.c (start_job_command): Reset execute_by_shell after an empty + command, like ":", has been seen. + +Tue Oct 07 15:00:00 1997 Phil Brooks + + * make.h [WINDOWS32]: make case sensitivity configurable + * dir.c [WINDOWS32]: make case sensitivity configurable + * README.W32: Document case sensitivity + * config.ami: Share case warping code with Windows + +Mon Oct 6 18:48:45 CDT 1997 Rob Tulloh + + * w32/subproc/sub_proc.c: Added support for MKS toolkit shell + (turn on HAVE_MKS_SHELL). + * read.c [WINDOWS32]: Fixed a problem with multiple target rules + reported by Gilbert Catipon (gcatipon@tibco.com). If multiple + path tokens in a rule did not have drive letters, make would + incorrectly concatenate the 2 tokens together. + * main.c/variable.c [WINDOWS32]: changed SHELL detection code to + follow what MSDOS did. In addition to watching for SHELL variable + updates, make's main will attempt to default the value of SHELL + before and after makefiles are parsed. + * job.c/job.h [WINDOWS32]: The latest changes made to enable use + of the GNUWIN32 shell from make could cause make to fail due to a + concurrency condition between parent and child processes. Make + now creates a batch file per job instead of trying to reuse the + same singleton batch file. + * job.c/job.h/function.c/config.h.W32 [WINDOWS32]: Renamed macro + from HAVE_CYGNUS_GNUWIN32_TOOLS to BATCH_MODE_ONLY_SHELL. Reworked + logic to reduce complexity. WINDOWS32 now uses the unixy_shell + variable to detect Bourne-shell compatible environments. There is + also a batch_mode_shell variable that determines whether not + command lines should be executed via script files. A WINDOWS32 + system with no sh.exe installed would have unixy_shell set to + FALSE and batch_mode_shell set to TRUE. If you have a unixy shell + that does not behave well when invoking things via 'sh -c xxx', + you may want to turn on BATCH_MODE_ONLY_SHELL and see if things + improve. + * NMakefile: Added /D DEBUG to debug build flags so that unhandled + exceptions could be debugged. + +Mon Oct 6 00:04:25 1997 Rob Tulloh + + * main.c [WINDOWS32]: The function define_variable() does not + handle NULL. Test before calling it to set Path. + * main.c [WINDOWS32]: Search Path again after makefiles have been + parsed to detect sh.exe. + * job.c [WINDOWS32]: Added support for Cygnus GNU WIN32 tools. + To use, turn on HAVE_CYGNUS_GNUWIN32_TOOLS in config.h.W32. + * config.h.W32: Added HAVE_CYGNUS_GNUWIN32_TOOLS macro. + +Sun Oct 5 22:43:59 1997 John W. Eaton + + * glob/glob.c (glob_in_dir) [VMS]: Globbing shouldn't be + case-sensitive. + * job.c (child_execute_job) [VMS]: Use a VMS .com file if the + command contains a newline (e.g. from a define/enddef block). + * vmsify.c (vmsify): Return relative pathnames wherever possible. + * vmsify.c (vmsify): An input string like "../.." returns "[--]". + +Wed Oct 1 15:45:09 1997 Rob Tulloh + + * NMakefile: Changed nmake to $(MAKE). + * subproc.bat: Take the make command name from the command + line. If no command name was given, default to nmake. + * job.c [MSDOS, WINDOWS32]: Fix memory stomp: temporary file names + are now always created in heap memory. + * w32/subproc/sub_proc.c: New implementation of make_command_line() + which is more compatible with different Bourne shell implementations. + Deleted the now obsolete fix_command_line() function. + * main.c [WINDOWS32]: Any arbitrary spelling of Path can be + detected. Make will ensure that the special spelling `Path' is + inserted into the environment when the path variable is propagated + within itself and to make's children. + * main.c [WINDOWS32]: Detection of sh.exe was occurring too + soon. The 2nd check for the existence of sh.exe must come after + the call to read_all_makefiles(). + +Fri Sep 26 01:14:18 1997 + + * makefile.com [VMS]: Fixed definition of sys. + * readme.vms: Comments on what's changed lately. + +Fri Sep 26 01:14:18 1997 John W. Eaton + + * read.c (read_all_makefiles): Allow make to find files named + "MAKEFILE" with no extension on VMS. + * file.c (lookup_file): Lowercase filenames on VMS. + +1997-09-29 Paul D. Smith + + * read.c (read_makefile): Reworked target detection again; the old + version had an obscure quirk. + +Fri Sep 19 09:20:49 1997 Paul D. Smith + + * Version 3.76.1 released. + + * Makefile.am: Add loadavg files to clean rules. + + * configure.in (AC_OUTPUT): Remove stamp-config; no longer needed. + * Makefile.ami (distclean): Ditto. + * SMakefile (distclean): Ditto. + + * main.c (main): Arg count should be int, not char! Major braino. + +Tue Sep 16 10:18:22 1997 Paul D. Smith + + * Version 3.76 released. + +Tue Sep 2 10:07:39 1997 Paul D. Smith + + * function.c (expand_function): When processing $(shell...) + translate a CRLF (\r\n) sequence as well as a newline (\n) to a + space. Also remove an ending \r\n sequence. + * make.texinfo (Shell Function): Document it. + +Fri Aug 29 12:59:06 1997 Rob Tulloh + + * w32/pathstuff.c (convert_Path_to_windows32): Fix problem where + paths which contain single character entries like `.' are not + handled correctly. + + * README.W32: Document path handling issues on Windows systems. + +Fri Aug 29 02:01:27 1997 Paul D. Smith + + * Version 3.75.93. + +Thu Aug 28 19:39:06 1997 Rob Tulloh + + * job.c (exec_command) [WINDOWS32]: If exec_command() is invoked + from main() to re-exec make, the call to execvp() would + incorrectly return control to parent shell before the exec'ed + command could run to completion. I believe this is a feature of + the way that execvp() is implemented on top of WINDOWS32 APIs. To + alleviate the problem, use the supplied process launch function in + the sub_proc library and suspend the parent process until the + child process has run. When the child exits, exit the parent make + with the exit code of the child make. + +Thu Aug 28 17:04:47 1997 Paul D. Smith + + * Makefile.DOS.template (distdir): Fix a line that got wrapped in + email. + + * Makefile.am (loadavg): Give the necessary cmdline options when + linking loadavg. + + * configure.in: Check for pstat_getdynamic for getloadvg on HP. + + * job.c (start_job_command) [VMS, _AMIGA]: Don't perform empty + command optimization on these systems; it doesn't make sense. + +Wed Aug 27 17:09:32 1997 Paul D. Smith + + * Version 3.75.92 + +Tue Aug 26 11:59:15 1997 Paul D. Smith + + * main.c (print_version): Add '97 to copyright years. + + * read.c (do_define): Check the length of the array before looking + at a particular offset. + + * job.c (construct_command_argv_internal): Examine the last byte + of the previous arg, not the byte after that. + +Sat Aug 23 1997 Eli Zaretskii + + * Makefile.DOS.template: New file (converted to Makefile.DOS in + the distribution). + + * configure.bat: Rewrite to use Makefile.DOS instead of editing + Makefile.in. Add support for building from outside of the source + directory. Fail if the environment block is too small. + + * configh.dos: Use . + + * README.DOS: Update instructions. + +Fri Aug 22 1997 Eli Zaretskii + + * job.c (start_job_command) [__MSDOS__]: Don't test for "/bin/sh" + literally, use value of unixy_shell instead. + + * filedef.h (NEW_MTIME): Use 1 less than maximum possible value if + time_t is unsigned. + +Sat Aug 16 00:56:15 1997 John W. Eaton + + * vmsify.c (vmsify, case 11): After translating `..' elements, set + nstate to N_OPEN if there are still more elements to process. + (vmsify, case 2): After translating `foo/bar' up to the slash, + set nstate to N_OPEN, not N_DOT. + +Fri Aug 8 15:18:09 1997 John W. Eaton + + * dir.c (vmsstat_dir): Leave name unmodified on exit. + * make.h (PATH_SEPARATOR_CHAR): Set to comma for VMS. + * vpath.c: Fix comments to refer to path separator, not colon. + (selective_vpath_search): Avoid Unixy slash handling for VMS. + +Thu Aug 7 22:24:03 1997 John W. Eaton + + * ar.c [VMS]: Don't declare ar_member_touch. + Delete VMS version of ar_member_date. + Enable non-VMS versions of ar_member_date and ar_member_date_1 for + VMS too. + * arscan.c (VMS_get_member_info): New function. + (ar_scan): Provide version for VMS systems. + (ar_name_equal): Simply compare name and mem on VMS systems. + Don't define ar_member_pos or ar_member_touch on VMS systems. + + * config.h-vms (pid_t, uid_t): Don't define. + + * remake.c: Delete declaration of vms_stat. + (name_mtime): Don't call vms_stat. + (f_mtime) [VMS]: Funky time value manipulation no longer necessary. + + * file.c (print_file): [VMS] Use ctime, not cvt_time. + + * make.h [VMS]: Don't define POSIX. + + * makefile.com (filelist): Include ar and arscan. + Also include them in the link commands. + Don't define NO_ARCHIVES in cc command. + + * makefile.vms (ARCHIVES, ARCHIVES_SRC): Uncomment. + (defines): Delete NO_ARCHIVES from list. + + * remake.c (f_mtime): Only check to see if intermediate file is + out of date if it also exists (i.e., mtime != (time_t) -1). + + * vmsdir.h (u_long, u_short): Skip typedefs if using DEC C. + +Fri Jun 20 23:02:07 1997 Rob Tulloh + + * w32/subproc/sub_proc.c: Get W32 sub_proc to handle shebang + (#!/bin/sh) in script files correctly. + Fixed a couple of memory leaks. + Fixed search order in find_file() (w32/subproc/sub_proc.c) so that + files with extensions are preferred over files without extensions. + Added search for files with .cmd extension too. + * w32/subproc/misc.c (arr2envblk): Fixed memory leak. + +Mon Aug 18 09:41:08 1997 Paul D. Smith + + * Version 3.75.91 + +Fri Aug 15 13:50:54 1997 Paul D. Smith + + * read.c (do_define): Remember to count the newline after the endef. + +Thu Aug 14 23:14:37 1997 Paul D. Smith + + * many: Rewrote builds to use Automake 1.2. + + * AUTHORS: New file. + * maintMakefile: Contains maintainer-only make snippets. + * GNUmakefile: This now only runs the initial auto* tools. + * COPYING,texinfo.tex,mkinstalldirs,install-sh: Removed (obtained + automatically by automake). + * compatMakefile: Removed (not needed anymore). + * README,build.sh.in: Removed (built from templates). + * config.h.in,Makefile.in: Removed (built by tools). + +Wed Aug 13 02:22:08 1997 Paul D. Smith + + * make.texinfo: Updates for DOS/Windows information (Eli Zaretskii) + * README,README.DOS: Ditto. + + * remake.c (update_file_1,f_mtime): Fix GPATH handling. + * vpath.c (gpath_search): Ditto. + + * file.c (rename_file): New function: rehash, but also rename to + the hashname. + * filedef.h: Declare it. + + * variable.c (merge_variable_set_lists): Remove free() of variable + set; since various files can share variable sets we don't want to + free them here. + +Tue Aug 12 10:51:54 1997 Paul D. Smith + + * configure.in: Require autoconf 2.12 + + * make.texinfo: Replace all "cd subdir; $(MAKE)" examples with a + more stylistically correct "cd subdir && $(MAKE)". + + * main.c: Global variable `clock_skew_detected' defined. + (main): Print final warning if it's set. + * make.h: Declare it. + * remake.c (f_mtime): Test and set it. + + * job.c (start_job_command): Add special optimizations for + "do-nothing" rules, containing just the shell no-op ":". This is + useful for timestamp files and can make a real difference if you + have a lot of them (requested by Fergus Henderson ). + + * configure.in,Makefile.in: Rewrote to use the new autoconf + program_transform_name macro. + + * function.c (function_strip): Strip newlines as well as spaces + and TABs. + +Fri Jun 6 23:41:04 1997 Rob Tulloh + + * remake.c (f_mtime): Datestamps on FAT-based files are rounded to + even seconds when stored, so if the date check fails on WINDOWS32 + systems, see if this "off-by-one" error is the problem. + + * General: If your TZ environment variable is not set correctly + then all your timestamps will be off by hours. So, set it! + +Mon Apr 7 02:06:22 1997 Paul D. Smith + + * Version 3.75.1 + + * compatMakefile (objs): Define & use the $(GLOB) variable so + that it's removed correctly from build.sh.in when it's built. + + * configure.in: On Solaris we can use the kstat_*() functions to + get load averages without needing special permissions. Add a + check for -lkstat to see if we have it. + + * getloadavg.c (getloadavg): Use HAVE_LIBKSTAT instead of SUN5 as + the test to enable kstat_open(), etc. processing. + +Fri Apr 4 20:21:18 1997 Eli Zaretskii + + * : Fixes to work in the DJGPP DOS environment. + +Mon Mar 31 02:42:52 1997 Paul D. Smith + + * function.c (expand_function): Added new function $(wordlist). + + * make.texinfo (Filename Functions): Document $(wordlist) function. + + * vpath.c (build_vpath_lists): Construct the GPATH variable + information in the same manner we used to construct VPATH. + (gpath_search): New function to search GPATH. + + * make.h: Declare the new function. + + * remake.c (update_file_1): Call it, and keep VPATH if it's found. + + * make.texinfo (Search Algorithm): Document GPATH variable. + +Sun Mar 30 20:57:16 1997 Paul D. Smith + + * main.c (handle_non_switch_argument): Defined the MAKECMDGOALS + variable to contain the user options passed in on the cmd line. + + * make.texinfo (Goals): Document MAKECMDGOALS variable. + + * remake.c (f_mtime): Print a warning if we detect a clock skew + error, rather than failing. + + * main.c (main): If we rebuild any makefiles and need to re-exec, + add "-o" options for each makefile rebuilt to avoid + infinite looping. + +Fri Mar 28 15:26:05 1997 Paul D. Smith + + * job.c (construct_command_argv_internal): Track whether the last + arg in the cmd string was empty or not (Roland). + (construct_command_argv_internal): If the shell line is empty, + don't do anything (Roland). + + * glob/glob.h,glob/glob.c,glob/fnmatch.c,glob/fnmatch.h: Install + the latest changes from the GLIBC version of glob (Ulrich Drepper). + + * getloadavg.c,make-stds.texi: New version (Roland). + + * (ALL): Changed WIN32 to W32 or WINDOWS32 (RMS). + +Mon Mar 24 15:33:34 1997 Rob Tulloh + + * README.W32: Describe preliminary FAT support. + + * build_w32.bat: Use a variable for the final exe name. + + * dir.c (find_directory): W32: Find the filesystem type. + (dir_contents_file_exists_p): W32: for FAT filesystems, always + rehash since FAT doesn't change directory mtime on change. + + * main.c (handle_runtime_exceptions): W32: Add an + UnhandledExceptionFilter so that when make bombs due to ^C or a + bug, it won't cause a GUI requestor to pop up unless debug is + turned on. + (main): Call it. + +Mon Mar 24 00:57:34 1997 Paul D. Smith + + * configure.in, config.h.in, config.ami, config.h-vms, config.h.w32: + Check for memmove() function. + + * make.h (bcopy): If memmove() available, define bcopy() to use it. + Otherwise just use bcopy(). Don't use memcpy(); it's not guaranteed + to handle overlapping moves. + + * read.c (read_makefile): Fix some uninitialized memory reads + (reported by Purify). + + * job.c (construct_command_argv_internal): Use bcopy() not + strcpy(); strcpy() isn't guaranteed to handle overlapping moves. + + * Makefile.in: Change install-info option ``--infodir'' to + ``--info-dir'' for use with new texinfo. + + * function.c (expand_function): $(basename) and $(suffix) should + only search for suffixes as far back as the last directory (e.g., + only the final filename in the path). + +Sun Mar 23 00:13:05 1997 Paul D. Smith + + * make.texinfo: Add @dircategory/@direntry information. + (Top): Remove previous reference to (dir) (from RMS). + (Static Usage): Add "all:" rule to example. + (Automatic Dependencies): fix .d file creation example. + + * Install VPATH+ patch: + + * filedef.h (struct file): Add in hname field to store the hashed + filename, and a flag to remember if we're using the vpath filename + or not. Renamed a few functions for more clarity. + + * file.c (lookup_file,enter_file,file_hash_enter): Store filenames + in the hash table based on their "hash name". We can change this + while keeping the original target in "name". + (rehash_file): Renamed from "rename_file" to be more accurate. + Changes the hash name, but not the target name. + + * remake.c (update_file_1): Modify -d output for more detailed + VPATH info. If we don't need to rebuild, use the VPATH name. + (f_mtime): Don't search for vpath if we're ignoring it. Call + renamed function rehash_file. Call name_mtime instead of + file_mtime, to avoid infinite recursion since the file wasn't + actually renamed. + + * implicit.c (pattern_search): if we find an implicit file in + VPATH, save the original name not the VPATH name. + + * make.texinfo (Directory Search): Add a section on the new VPATH + functionality. + +Sun Dec 1 18:36:04 1996 Andreas Schwab + + * dir.c (file_exists_p, file_impossible, file_impossible_p): If + dirname is empty replace it by the name of the root directory. + Note that this doesn't work (yet) for W32, Amiga, or VMS. + +Tue Oct 08 13:57:03 1996 Rob Tulloh + + * main.c (main): W32 bug fix for PATH vars. + +Tue Sep 17 1996 Paul Eggert + + * filedef.h (NEW_MTIME): Don't assume that time_t is a signed + 32-bit quantity. + + * make.h: (CHAR_BIT, INTEGER_TYPE_SIGNED, INTEGER_TYPE_MAXIMUM, + INTEGER_TYPE_MINIMUM): New macros. + +Tue Aug 27 01:06:34 1996 Roland McGrath + + * Version 3.75 released. + + * main.c (print_version): Print out bug-reporting address. + +Mon Aug 26 19:55:47 1996 Roland McGrath + + * main.c (print_data_base): Don't declare ctime; headers do it for us + already. + +Sun Jul 28 15:37:09 1996 Rob Tulloh (tulloh@tivoli.com) + + * w32/pathstuff.c: Turned convert_vpath_to_w32() into a + real function. This was done so that VPATH could contain + white space separated pathnames. Please note that directory + paths (in VPATH/vpath context) containing white space are not + supported (just as they are not under Unix). See README.W32 + for suggestions. + + * w32/include/pathstuff.h: Added prototype for the new + function convert_vpath_to_w32. Deleted macro for same. + + * README.W32: Added some notes about why I chose not to try + and support pathnames which contain white space and some + workaround suggestions. + +Thu Jul 25 19:53:31 1996 Roland McGrath + + * GNUmakefile (mkdep-nolib): Use -MM option unconditionally. + + * Version 3.74.7. + + * main.c (define_makeflags): Back up P to point at null terminator + when killing final space and dash before setting MFLAGS. + + From Robert Hoehne : + * dir.c [__MSDOS__ && DJGPP > 1]: Include and defin + `__opendir_flags' initialized to 0. + (dosify) [__MSDOS__ && DJGPP > 1]: Return name unchanged if _USE_LFN. + (find_directory) [__MSDOS__ && DJGPP > 1]: If _USE_LGN, set + __opendir_flags to __OPENDIR_PRESERVE_CASE. + + * vmsfunctions.c (vms_stat): `sys$dassgn (DevChan);' added by kkaempf. + + * GNUmakefile (w32files): Add NMakefile. + + * NMakefile (LDFLAGS_debug): Value fixed by tulloh. + +Sat Jul 20 12:32:10 1996 Klaus Kämpf (kkaempf@progis.de) + + * remake.c (f_mtime) [VMS]: Add missing `if' conditional for future + modtime check. + * config.h-vms, makefile.vms, readme.vms, vmsify.c: Update address. + +Sat Jul 20 05:29:43 1996 Roland McGrath + + * configure.in: Require autoconf 2.10 or later. + +Fri Jul 19 16:57:27 1996 Roland McGrath + + * Version 3.74.6. + + * GNUmakefile (w32files): New variable. + (distfiles): Add it. + * w32: Updated by Rob Tulloh. + + * makefile.vms (LOADLIBES): Fix typo. + +Sun Jul 14 12:59:27 1996 Roland McGrath + + * job.c (construct_command_argv_internal): Fix up #else, #endifs. + + * configh.dos: Define HAVE_DIRENT_H instead of DIRENT. + + * remake.c (f_mtime): Don't compare MTIME to NOW if MTIME == -1. + + * Version 3.74.5. + + * main.c (main): Exit with status 2 when update_goal_chain returns 2. + +Sat Jun 22 14:56:05 1996 Roland McGrath + + * configure.in: Don't check for _sys_siglist. + * make.h [HAVE__SYS_SIGLIST]: Don't test this; just punt if there is + no strsignal or sys_siglist. + + * read.c (conditional_line): Strip ws in `ifeq (a , b)' so it is the + same as `ifeq (a, b)'. + + * job.c (reap_children): Don't call die if handling_fatal_signal. + + * file.c (file_hash_enter): Allow renaming :: to : when latter is + non-target, or : to :: when former is non-target. + + * job.c (start_job_command): Call block_sigs. + (block_sigs): New function, broken out of start_job_command. + (reap_children): Block fatal signals around removing dead child from + chain and adjusting job_slots_used. + * job.h: Declare block_sigs. + + * remote-stub.c (remote_setup, remote_cleanup): New (empty) functions. + * main.c (main): Call remote_setup. + (die): Call remote_cleanup. + + * job.c (reap_children): Quiescent value of shell_function_pid is + zero, not -1. + + * main.c (print_version): Add 96 to copyright years. + +Sat Jun 15 20:30:01 1996 Andreas Schwab + + * read.c (find_char_unquote): Avoid calling strlen on every call + just to throw away the value most of the time. + +Sun Jun 2 12:24:01 1996 Roland McGrath + + * main.c (decode_env_switches): Prepend '-' to ARGV[1] if it contains + no '=', regardless of ARGC. + (define_makeflags): Elide leading '-' from MAKEFLAGS value if first + word is short option, regardless of WORDS. + +Wed May 22 17:24:51 1996 Roland McGrath + + * makefile.vms: Set LOADLIBES. + * makefile.com (link_using_library): Fix typo. + +Wed May 15 17:37:26 1996 Roland McGrath + + * dir.c (print_dir_data_base): Use %ld dev and ino and cast them to + long. + +Wed May 15 10:14:14 CDT 1996 Rob Tulloh + + * dir.c: W32 does not support inode. For now, fully qualified + pathname along with st_mtime will be keys for files. + Fixed problem where vpath can be confused when files + are added to a directory after the directory has already been + read in. The code now attempts to reread the directory if it + discovers that the datestamp on the directory has changed since + it was cached by make. This problem only seems to occur on W32 + right now so it is lumped under port #ifdef WINDOWS32. + + * function.c: W32: call subproc library (CreateProcess()) instead of + fork/exec. + + * job.c: W32: Added the code to do fork/exec/waitpid style processing + on W32 systems via calls to subproc library. + + * main.c: W32: Several things added here. First, there is code + for dealing with PATH and SHELL defaults. Make tries to figure + out if the user has %PATH% set in the environment and sets it to + %Path% if it is not set already. Make also looks to see if sh.exe + is anywhere to be found. Code path through job.c will change + based on existence of a working Bourne shell. The checking for + default shell is done twice: once before makefiles are read in + and again after. Fall back to MSDOS style execution mode if no sh.exe + is found. Also added some debug support that allows user to pause make + with -D switch and attach a debugger. This is especially useful for + debugging recursive calls to make where problems appear only in the + sub-make. + + * make.h: W32: A few macros and header files for W32 support. + + * misc.c: W32: Added a function end_of_token_w32() to assist + in parsing code in read.c. + + * read.c: W32: Fixes similar to MSDOS which allow colon to + appear in filenames. Use of colon in filenames would otherwise + confuse make. + + * remake.c: W32: Added include of io.h to eliminate compiler + warnings. Added some code to default LIBDIR if it is not set + on W32. + + * variable.c: W32: Added support for detecting Path/PATH + and converting them to semicolon separated lists for make's + internal use. New function sync_Path_environment() + which is called in job.c and function.c before creating a new + process. Caller must set Path in environment since we don't + have fork() to do this for us. + + * vpath.c: W32: Added detection for filenames containing + forward or backward slashes. + + * NMakefile: W32: Visual C compatible makefile for use with nmake. + Use this to build GNU make the first time on Windows NT or Windows 95. + + * README.W32: W32: Contains some helpful notes. + + * build_w32.bat: W32: If you don't like nmake, use this the first + time you build GNU make on Windows NT or Windows 95. + + * config.h.W32: W32 version of config.h + + * subproc.bat: W32: A bat file used to build the + subproc library from the top-level NMakefile. Needed because + WIndows 95 (nmake) doesn't allow you to cd in a make rule. + + * w32/include/dirent.h + * w32/compat/dirent.c: W32: opendir, readdir, closedir, etc. + + * w32/include/pathstuff.h: W32: used by files needed functions + defined in pathstuff.c (prototypes). + + * w32/include/sub_proc.h: W32: prototypes for subproc.lib functions. + + * w32/include/w32err.h: W32: prototypes for w32err.c. + + * w32/pathstuff.c: W32: File and Path/Path conversion functions. + + * w32/subproc/build.bat: W32: build script for subproc library + if you don't wish to use nmake. + + * w32/subproc/NMakefile: W32: Visual C compatible makefile for use + with nmake. Used to build subproc library. + + * w32/subproc/misc.c: W32: subproc library support code + * w32/subproc/proc.h: W32: subproc library support code + * w32/subproc/sub_proc.c: W32: subproc library source code + * w32/subproc/w32err.c: W32: subproc library support code + +Mon May 13 14:37:42 1996 Roland McGrath + + * Version 3.74.4. + + * GNUmakefile (vmsfiles): Fix typo. + + * GNUmakefile (amigafiles): Add amiga.h. + +Sun May 12 19:19:43 1996 Aaron Digulla + + * dir.c: New function: amigafy() to fold filenames + Changes HASH() to HASHI() to fold filenames on Amiga. + Stringcompares use strieq() instead of streq() + The current directory on Amiga is "" instead of "." + * file.c: Likewise. + + * amiga.c: New function wildcard_expansion(). Allows to use + Amiga wildcards with $(wildcard ) + + * amiga.h: New file. Prototypes for amiga.c + + * function.c: Use special function wildcard_expansion() for + $(wildcard ) to allow Amiga wildcards + The current directory on Amiga is "" instead of "." + + * job.c: No Pipes on Amiga, too + (load_too_high) Neither on Amiga + ENV variable on Amiga are in a special directory and are not + passed as third argument to main(). + + * job.h: No envp on Amiga + + * make.h: Added HASHI(). This is the same as HASH() but converts + it's second parameter to lowercase on Amiga to fold filenames. + + * main.c: (main), variable.c Changed handling of ENV-vars. Make + stores now the names of the variables only and reads their contents + when they are accessed to reflect that these variables are really + global (i.e., they CAN change WHILE make runs !) This handling is + made in lookup_variable() + + * Makefile.ami: renamed file.h to filedep.h + Updated dependencies + + * read.c: "find_semicolon" is declared as static but never defined. + No difference between Makefile and makefile on Amiga; added + SMakefile to *default_makefiles[]. + (read_makefile) SAS/C want's two_colon and pattern_percent be set + before use. + The current directory on Amiga is "" instead of "." + Strange #endif moved. + + * README.Amiga: updated feature list + + * SMakefile: Updated dependencies + + * variable.c: Handling of ENV variable happens inside lookup_variable() + +Sat May 11 17:58:32 1996 Roland McGrath + + * variable.c (try_variable_definition): Count parens in lhs variable + refs to avoid seeing =/:=/+= inside a ref. + +Thu May 9 13:54:49 1996 Roland McGrath + + * commands.c (fatal_error_signal) [SIGQUIT]: Make SIGQUIT check + conditional. + + * main.c (main): Use unsigned for fread return. + + * read.c (parse_file_seq): Use `int' for char arg to avoid widening + conflict issues. + * dep.h: Fix prototype. + + * function.c (expand_function) [_AMIGA]: Fix some typos. + (patsubst_expand): Make len vars unsigned. + + * GNUmakefile (globfiles): Add AmigaDOS support files. + (distfiles): Add $(amigafiles). + (amigafiles): New variable. + +Thu Nov 7 10:18:16 1995 Aaron Digulla + + * Added Amiga support in commands.c, dir.c, function.c, + job.c, main.c, make.h, read.c, remake.c + * commands.c: Amiga has neither SIGHUP nor SIGQUIT + * dir.c: Amiga has filenames with Upper- and Lowercase, + but "FileName" is the same as "filename". Added strieq() + which is use to compare filenames. This is like streq() + on all other systems. Also there is no such thing as + "." under AmigaDOS. + * function.c: On Amiga, the environment is not passed as envp, + there are no pipes and Amiga can't fork. Use my own function + to create a new child. + * job.c: default_shell is "" (The system automatically chooses + a shell for me). Have to use the same workaround as MSDOS for + running batch commands. Added HAVE_SYS_PARAM_H. NOFILE isn't + known on Amiga. Cloned code to run children from MSDOS. Own + version of sh_chars[] and sh_cmds[]. No dup2() or dup() on Amiga. + * main.c: Force stack to 20000 bytes. Read environment from ENV: + device. On Amiga, exec_command() does return, so I exit() + afterwards. + * make.h: Added strieq() to compare filenames. + * read.c: Amiga needs special extension to have passwd. Only + one include-dir. "Makefile" and "makefile" are the same. + Added "SMakefile". Added special code to handle device names (xxx:) + and "./" in rules. + * remake.c: Only one lib-dir. Amiga link-libs are named "%s.lib" + instead of "lib%s.a". + * main.c, rule.c, variable.c: Avoid floats at all costs. + * vpath.c: Get rid of as many alloca()s as possible. + +Thu May 9 13:20:43 1996 Roland McGrath + + * read.c (read_makefile): Grok `sinclude' as alias for `-include'. + +Wed Mar 20 09:52:27 1996 Roland McGrath + + * GNUmakefile (vmsfiles): New variable. + (distfiles): Include $(vmsfiles). + +Tue Mar 19 20:21:34 1996 Roland McGrath + + Merged VMS port from Klaus Kaempf . + * make.h (PARAMS): New macro. + * config.h-vms: New file. + * makefile.com: New file. + * makefile.vms: New file. + * readme.vms: New file. + * vmsdir.h: New file. + * vmsfunctions.c: New file. + * vmsify.c: New file. + * file.h: Renamed to filedef.h to avoid conflict with VMS system hdr. + * ar.c: Added prototypes and changes for VMS. + * commands.c: Likewise. + * commands.h: Likewise. + * default.c: Likewise. + * dep.h: Likewise. + * dir.c: Likewise. + * expand.c: Likewise. + * file.c: Likewise. + * function.c: Likewise. + * implicit.c: Likewise. + * job.c: Likewise. + * job.h: Likewise. + * main.c: Likewise. + * make.h: Likewise. + * misc.c: Likewise. + * read.c: Likewise. + * remake.c: Likewise. + * remote-stub.c: Likewise. + * rule.c: Likewise. + * rule.h: Likewise. + * variable.c: Likewise. + * variable.h: Likewise. + * vpath.c: Likewise. + * compatMakefile (srcs): Rename file.h to filedef.h. + +Sat Aug 19 23:11:00 1995 Richard Stallman + + * remake.c (check_dep): For a secondary file, try implicit and + default rules if appropriate. + +Wed Aug 2 04:29:42 1995 Richard Stallman + + * remake.c (check_dep): If an intermediate file exists, + do consider its actual date. + +Sun Jul 30 00:49:53 1995 Richard Stallman + + * file.h (struct file): New field `secondary'. + * file.c (snap_deps): Check for .INTERMEDIATE and .SECONDARY. + (remove_intermediates): Don't delete .SECONDARY files. + +Sat Mar 2 16:26:52 1996 Roland McGrath + + * compatMakefile (srcs): Add getopt.h; prepend $(srcdir)/ to getopt*. + +Fri Mar 1 12:04:47 1996 Roland McGrath + + * Version 3.74.3. + + * remake.c (f_mtime): Move future modtime check before FILE is + clobbered by :: loop. + + * dir.c: Use canonical code from autoconf manual for dirent include. + [_D_NAMLEN]: Redefine NAMLEN using this. + (dir_contents_file_exists_p): Use NAMLEN macro. + (read_dirstream) [_DIRENT_HAVE_D_NAMLEN]: Only set d_namlen #if this. + + * compatMakefile (objs): Add missing backslash. + +Wed Feb 28 03:56:20 1996 Roland McGrath + + * default.c (default_terminal_rules): Remove + prefix from RCS cmds. + (default_variables): Put + prefix in $(CHECKOUT,v) value instead. + + * remake.c (f_mtime): Check for future timestamps; give error and mark + file as "failed to update". + +Fri Jan 12 18:09:36 1996 Roland McGrath + + * job.c: Don't declare unblock_sigs; job.h already does. + +Sat Jan 6 16:24:44 1996 Roland McGrath + + * acconfig.h (HAVE_SYSCONF_OPEN_MAX): #undef removed. + + * job.c (NGROUPS_MAX): Don't try to define this macro. + +Fri Dec 22 18:44:44 1995 Roland McGrath + + * compatMakefile (GETOPT, GETOPT_SRC, GLOB): Variables removed. + (objs, srcs): Include their values here instead of references. + +Thu Dec 14 06:21:29 1995 Roland McGrath + + * Version 3.74.2. + + * job.c (reap_children): Call unblock_sigs after start_job_command. + +Thu Dec 14 07:22:03 1995 Roland McGrath + + * dir.c (dir_setup_glob): Don't use lstat; glob never calls it anyway. + Avoid & before function names to silence bogus sunos4 compiler. + + * configure.in: Remove check for `sysconf (_SC_OPEN_MAX)'. + +Tue Dec 12 00:48:42 1995 Roland McGrath + + * Version 3.74.1. + + * dir.c (read_dirstream): Fix braino: fill in the buffer when not + reallocating it! + +Mon Dec 11 22:26:15 1995 Roland McGrath + + * misc.c (collapse_continuations): Fix skipping of trailing \s so + it can never dereference before the beginning of the array. + + * read.c (find_semicolon): Function removed. + (read_makefile): Don't use find_semicolon or remove_comments for + rule lines. Use find_char_unquote directly and handle quoted comments + properly. + + * default.c: Remove all [M_XENIX] code. + + * dir.c [HAVE_D_NAMLEN]: Define this for __GNU_LIBRARY__ > 1. + (D_NAMLEN): Macro removed. + (FAKE_DIR_ENTRY): New macro. + (dir_contents_file_exists_p): Test HAVE_D_NAMLEN instead of using + D_NAMLEN. + (read_dirstream): Return a struct dirent * for new glob interface. + (init_dir): Function removed. + (dir_setup_glob): New function. + * main.c (main): Don't call init_dir. + * read.c (multi_glob): Call dir_setup_glob on our glob_t and use + GLOB_ALTDIRFUNC flag. + + * misc.c (safe_stat): Function removed. + * read.c, commands.c, remake.c, vpath.c: Use plain stat instead of + safe_stat. + +Sat Nov 25 20:35:18 1995 Roland McGrath + + * job.c [HAVE_UNION_WAIT]: Include sys/wait.h. + + * main.c (log_working_directory): Made global. + Print entering msg only once. + * make.h (log_working_directory): Declare it. + * misc.c (message): Take new arg PREFIX. Print "make: " only if + nonzero. Call log_working_directory. + * remake.c: Pass new arg in `message' calls. + * job.c (start_job_command): Pass new arg to `message'; fix + inverted test in that call. + +Tue Nov 21 19:01:12 1995 Roland McGrath + + * job.c (start_job_command): Use `message' to print the command, + and call it with null if the command is silent. + * remake.c (touch_file): Use message instead of printf. + +Tue Oct 10 14:59:30 1995 Roland McGrath + + * main.c (enter_command_line_file): Barf if NAME is "". + +Sat Sep 9 06:33:20 1995 Roland McGrath + + * commands.c (delete_target): Ignore unlink failure if it is ENOENT. + +Thu Aug 17 15:08:57 1995 Roland McGrath + + * configure.in: Don't check for getdtablesize. + * job.c (getdtablesize): Remove decls and macros. + +Thu Aug 10 19:10:03 1995 Roland McGrath + + * main.c (define_makeflags): Omit command line variable + definitions from MFLAGS value. + + * arscan.c (ar_scan) [AIAMAG]: Check for zero MEMBER_OFFSET, + indicating a valid, but empty, archive. + +Mon Aug 7 15:40:03 1995 Roland McGrath + + * dir.c (file_impossible_p): Correctly reset FILENAME to name + within directory before hash search. + + * job.c (child_error): Do nothing if IGNORED under -s. + + * job.c (exec_command): Correctly use ARGV[0] for script name when + running shell directly. + +Tue Aug 1 14:39:14 1995 Roland McGrath + + * job.c (child_execute_job): Close STDIN_FD and STDOUT_FD after + dup'ing from them. Don't try to close all excess descriptors; + getdtablesize might return a huge value. Any open descriptors in + the parent should have FD_CLOEXEC set. + (start_job_command): Set FD_CLOEXEC flag on BAD_STDIN descriptor. + +Tue Jun 20 03:47:15 1995 Roland McGrath + + * read.c (read_all_makefiles): Properly append default makefiles + to the end of the `read_makefiles' chain. + +Fri May 19 16:36:32 1995 Roland McGrath + + * Version 3.74 released. + +Wed May 10 17:43:34 1995 Roland McGrath + + * Version 3.73.3. + +Tue May 9 17:15:23 1995 Roland McGrath + + * compatMakefile ($(infodir)/make.info): Make sure $$dir is set in + install-info cmd. + +Wed May 3 15:56:06 1995 Roland McGrath + + * file.c (print_file): Grok update_status of 1 for -q. + +Thu Apr 27 12:39:35 1995 Roland McGrath + + * Version 3.73.2. + +Wed Apr 26 17:15:57 1995 Roland McGrath + + * file.c (remove_intermediates): Fix inverted test to bail under + -n for signal case. Bail under -q or -t. + Skip files with update_status==-1. + + * job.c (job_next_command): Skip empty lines. + (new_job): Don't test the return of job_next_command. + Just let start_waiting_job handle the case of empty commands. + +Wed Apr 19 03:25:54 1995 Roland McGrath + + * function.c [__MSDOS__]: Include . From DJ Delorie. + + * Version 3.73.1. + +Sat Apr 8 14:53:24 1995 Roland McGrath + + * remake.c (notice_finished_file): Set FILE->update_status to zero + if it's -1. + +Wed Apr 5 00:20:24 1995 Roland McGrath + + * Version 3.73 released. + +Tue Mar 28 13:25:46 1995 Roland McGrath + + * main.c (main): Fixed braino in assert. + + * Version 3.72.13. + +Mon Mar 27 05:29:12 1995 Roland McGrath + + * main.c: Avoid string in assert expression. Some systems are broken. + +Fri Mar 24 00:32:32 1995 Roland McGrath + + * main.c (main): Handle 1 and 2 returns from update_goal_chain + makefile run properly. + + * Version 3.72.12. + + * main.c (handle_non_switch_argument): New function, broken out of + decode_switches. + (decode_switches): Set optind to 0 to reinitialize getopt, not to 1. + When getopt_long returns EOF, break the loop and handle remaining args + with a simple second loop. + + * remake.c (remake_file): Set update_status to 2 instead of 1 for + no rule to make. Mention parent (dependent) in error message. + (update_file_1): Handle FILE->update_status == 2 in -d printout. + * job.c (start_job_command, reap_children): Set update_status to 2 + instead of 1 for failed commands. + +Tue Mar 21 16:23:38 1995 Roland McGrath + + * job.c (search_path): Function removed (was already #if 0'd out). + * configure.in: Remove AC_TYPE_GETGROUPS; nothing needs it any more. + +Fri Mar 17 15:57:40 1995 Roland McGrath + + * configure.bat: Write @CPPFLAGS@ translation. + +Mon Mar 13 00:45:59 1995 Roland McGrath + + * read.c (parse_file_seq): Rearranged `l(a b)' -> `l(a) l(b)' loop + to not skip the elt immediately preceding `l(...'. + +Fri Mar 10 13:56:49 1995 Roland McGrath + + * Version 3.72.11. + + * read.c (find_char_unquote): Make second arg a string of stop + chars instead of a single stop char. Stop when any char in the + string is hit. All callers changed. + (find_semicolon): Pass stop chars "#;" to one find_char_unquote call, + instead of using two calls. If the match is not a ; but a #, + return zero. + * misc.c: Changed find_char_unquote callers here too. + + * Version 3.72.10. + + * read.c (read_makefile, parse_file_seq): Fix typo __MS_DOS__ -> + __MSDOS__. + + * GNUmakefile (globfiles): Add glob/configure.bat. + (distfiles): Add configh.dos, configure.bat. + +Wed Mar 8 13:10:57 1995 Roland McGrath + + Fixes for MS-DOS from DJ Delorie. + * read.c (read_makefile, parse_file_seq) [__MS_DOS__]: Don't see : + as separator in "C:\...". + * configh.dos (STDC_HEADERS): Define only if undefined. + (HAVE_SYS_PARAM_H): Don't define this. + (HAVE_STRERROR): Define this. + * job.c (construct_command_argv_internal) [__MSDOS__]: Fix typos. + + * Version 3.72.9. + + * main.c (decode_switches): Reset optind to 1 instead of 0. + +Tue Mar 7 17:31:06 1995 Roland McGrath + + * main.c (decode_switches): If non-option arg is "-", ignore it. + +Mon Mar 6 23:57:38 1995 Roland McGrath + + * Version 3.72.8. + +Wed Feb 22 21:26:36 1995 Roland McGrath + + * Version 3.72.7. + +Tue Feb 21 22:10:43 1995 Roland McGrath + + * main.c (main): Pass missing arg to tmpnam. + + * configure.in: Check for strsignal. + * job.c (child_error): Use strsignal. + * main.c (main): Don't call signame_init #ifdef HAVE_STRSIGNAL. + + * misc.c (strerror): Fix swapped args in sprintf. + +Mon Feb 13 11:50:08 1995 Roland McGrath + + * configure.in (CFLAGS, LDFLAGS): Don't set these variables. + +Fri Feb 10 18:44:12 1995 Roland McGrath + + * main.c (print_version): Add 95 to copyright years. + + * Version 3.72.6. + + * job.c (start_job_command): Remember to call notice_finished_file + under -n when not recursing. To do this, consolidate that code + under the empty command case and goto there for the -n case. + +Tue Feb 7 13:36:03 1995 Roland McGrath + + * make.h [! STDC_HEADERS]: Don't declare qsort. Sun headers + declare it int. + +Mon Feb 6 17:37:01 1995 Roland McGrath + + * read.c (read_makefile): For bogus line starting with tab, ignore + it if blank after removing comments. + + * main.c: Cast results of `alloca' to `char *'. + * expand.c: Likewise. + +Sun Feb 5 18:35:46 1995 Roland McGrath + + * Version 3.72.5. + + * configure.in: Check for mktemp. + * main.c (main) [! HAVE_MKTEMP]: Use tmpnam instead of mktemp. + + * configure.in (make_cv_sysconf_open_max): New check for `sysconf + (_SC_OPEN_MAX)'. + * acconfig.h: Added #undef HAVE_SYSCONF_OPEN_MAX. + * job.c [HAVE_SYSCONF_OPEN_MAX] (getdtablesize): Define as macro + using sysconf. + +Fri Jan 27 04:42:09 1995 Roland McGrath + + * remake.c (update_file_1): When !MUST_MAKE, don't set + FILE->update_status to zero before calling notice_finished_file. + (notice_finished_file): Touch only when FILE->update_status is zero. + (remake_file): Set FILE->update_status to zero after not calling + execute_file_command and deciding to touch instead. + +Thu Jan 26 01:29:32 1995 Roland McGrath + + * main.c (debug_signal_handler): New function; toggles debug_flag. + (main): Handle SIGUSR1 with that. + +Mon Jan 16 15:46:56 1995 Roland McGrath + + * compatMakefile (realclean): Remove Info files. + +Sun Jan 15 08:23:09 1995 Roland McGrath + + * Version 3.72.4. + + * job.c (start_job_command): Save and restore environ around vfork + call. + (search_path): Function #if 0'd out. + (exec_command): Use execvp instead of search_path. + + * expand.c (variable_expand): Rewrote computed variable name and + substitution reference handling to be simpler. First expand the + entire text between the parens if it contains any $s, then examine + the result of that for subtitution references and do no further + expansion while parsing them. + + * job.c (construct_command_argv_internal): Handle " quoting too, + when no backslash, $ or ` characters appear inside the quotes. + + * configure.in (union wait check): If WEXITSTATUS and WTERMSIG are + defined, just use int. + +Tue Jan 10 06:27:27 1995 Roland McGrath + + * default.c (default_variables) [__hpux]: Remove special + definition of ARFLAGS. Existence of the `f' flag is not + consistent across HPUX versions; and one might be using GNU ar + anyway. + + * compatMakefile (clean): Don't remove Info files. + + * compatMakefile (check): Remove gratuitous target declaration. + +Sat Jan 7 11:38:23 1995 Roland McGrath + + * compatMakefile (ETAGS, CTAGS): Don't use -t. + + * arscan.c (ar_name_equal) [cray]: Subtract 1 like [__hpux]. + + * main.c (decode_switches): For --help, print usage to stdout. + +Mon Dec 5 12:42:18 1994 Roland McGrath + + * Version 3.72.3. + + * remake.c (update_file_1): Do set_command_state (FILE, + cs_not_started) only if old state was deps_running. + +Mon Nov 28 14:24:03 1994 Roland McGrath + + * job.c (start_waiting_job): Use set_command_state. + + * build.template (CPPFLAGS): New variable. + (prefix, exec_prefix): Set from @...@. + (compilation loop): Pass $CPPFLAGS to compiler. + + * GNUmakefile (build.sh.in): Make it executable. + + * GNUmakefile (globfiles): Add configure.in, configure. + + * Version 3.72.2. + + * configure.in (AC_OUTPUT): Don't write glob/Makefile. + + * configure.in (AC_CHECK_SYMBOL): Use AC_DEFINE_UNQUOTED. + + * configure.in: Don't check for ranlib. + +Tue Nov 22 22:42:40 1994 Roland McGrath + + * remake.c (notice_finished_file): Only mark also_make's as + updated if really ran cmds. + +Tue Nov 15 06:32:46 1994 Roland McGrath + + * configure.in: Put dnls before random whitespace. + +Sun Nov 13 05:02:25 1994 Roland McGrath + + * compatMakefile (CPPFLAGS): New variable, set from @CPPFLAGS@. + (RANLIB): Variable removed. + (prefix, exec_prefix): Set these from @...@. + (.c.o): Use $(CPPFLAGS). + (glob/libglob.a): Don't pass down variables to sub-make. + glob/Makefile should be configured properly by configure. + (distclean): Remove config.log and config.cache (autoconf stuff). + +Mon Nov 7 13:58:06 1994 Roland McGrath + + * acconfig.h: Add #undef HAVE_UNION_WAIT. + * configure.in: Converted to Autoconf v2. + * dir.c: Test HAVE_DIRENT_H, HAVE_SYS_DIR_H, HAVE_NDIR_H instead + of DIRENT, SYSDIR, NDIR. + * build.sh.in (prefix, exec_prefix): Set these from @...@. + (CPPFLAGS): New variable, set from @CPPFLAGS@. + (compiling loop): Pass $CPPFLAGS before $CFLAGS. + * install.sh: File renamed to install-sh. + + * main.c (define_makeflags): When no flags, set WORDS to zero. + +Sun Nov 6 18:34:01 1994 Roland McGrath + + * Version 3.72.1. + + * main.c (define_makeflags): Terminate properly when FLAGSTRING is + empty. + +Fri Nov 4 16:02:51 1994 Roland McGrath + + * Version 3.72. + +Tue Nov 1 01:18:10 1994 Roland McGrath + + * Version 3.71.5. + + * job.c (start_job_command): When ARGV is nil, only set + update_state and call notice_finished_file if job_next_command + returns zero. + + * job.c (start_job_command): Call notice_finished_file for empty + command line. + +Thu Oct 27 02:02:45 1994 Roland McGrath + + * file.c (snap_deps): Set COMMANDS_SILENT for .SILENT, not + COMMANDS_NOERROR. + +Wed Oct 26 02:14:10 1994 Roland McGrath + + * Version 3.71.4. + +Tue Oct 25 22:49:24 1994 Roland McGrath + + * file.c (snap_deps): Set command_flags bits in all :: entries. + +Mon Oct 24 18:47:50 1994 Roland McGrath + + * make.h (posix_pedantic): Declare it. + * main.c (main): Move checks .IGNORE, .SILENT, .POSIX to + snap_deps. + * file.c (snap_deps): Check .IGNORE, .SILENT, .POSIX here instead + of in main. If .IGNORE has deps, OR COMMANDS_NOERROR into their + command_flags and don't set -i. Likewise .SILENT. + * job.c (start_job_command): In FLAGS initialization, OR in + CHILD->file->command_flags. + * file.h (struct file): New member `command_flags'. + +Sun Oct 16 01:01:51 1994 Roland McGrath + + * main.c (switches): Bump flag values for --no-print-directory and + --warn-undefined-variables, so neither is 1 (which indicates a + nonoption argument). + +Sat Oct 15 23:39:48 1994 Roland McGrath + + * main.c (main): Add missing code in .IGNORE test. + +Mon Oct 10 04:09:03 1994 Roland McGrath + + * variable.c (define_automatic_variables): Define +D and +F. + +Sat Oct 1 04:07:48 1994 Roland McGrath + + * main.c (main): Define hidden automatic variable with command + vars, and MAKEOVERRIDES to a reference to that. + (define_makeflags): If posix_pedantic, write a reference to that + instead. + +Thu Sep 29 00:14:26 1994 Roland McGrath + + * main.c (posix_pedantic): New variable. + (main): Set posix_pedantic if .POSIX is a target. + Fix .IGNORE and .SILENT checks to require is_target. + + * commands.c (set_file_variables): Define new automatic variable + $+, like $^ but before calling uniquize_deps. + + * job.c (reap_children): Call delete_child_targets for non-signal + error if .DELETE_ON_ERROR is a target. + +Tue Sep 27 01:57:14 1994 Roland McGrath + + * Version 3.71.3. + +Mon Sep 26 18:16:55 1994 Roland McGrath + + * job.c (reap_children): Don't change C->file->command_state when + dying. Test it only after calling start_job_command for a new + command line. When no more cmds, just set C->file->update_status. + (start_job_command): When the last line is empty or under -n, set + C->file->update_status. + (start_waiting_job): Grok cs_not_started after start_job_command + as success. + (new_job): Set C->file->update_status when there are no cmds. + (job_next_command): When out of lines, don't set + CHILD->file->update_status or CHILD->file->command_state. + + * main.c (quote_as_word): Renamed from shell_quote. Take new arg; + if nonzero, also double $s. + (main): Define MAKEOVERRIDES from command_variables here. + (define_makeflags): Don't use command_variables here; instead write a + reference $(MAKEOVERRIDES) in MAKEFLAGS. Make vars recursive. + + * dir.c [__MSDOS__]: Fixed typo. + + * vpath.c (selective_vpath_search): Reset EXISTS when stat fails. + +Sat Sep 10 03:01:35 1994 Roland McGrath + + * remake.c: Include and use assert instead of printfs + and abort. + + * main.c (decode_switches): Loop until optind hits ARGC, not just + until getopt_long returns EOF. Initialize C to zero before loop; + in loop if C is EOF, set optarg from ARGV[optind++], else call + getopt_long. + (decode_env_switches): Use variable_expand instead of + allocated_variable_expand. Allocate a fresh buffer to copy split + words into; scan characters by hand to break words and + debackslashify. + (shell_quote): New function. + (define_makeflags): Allocate doubled space for switch args, and command + variable names and values; use shell_quote to quote those things. + +Fri Sep 9 01:37:47 1994 Roland McGrath + + * Version 3.71.2. + + * acconfig.h: Add HAVE_SYS_SIGLIST and HAVE__SYS_SIGLIST. + + * main.c (decode_switches): The non-option return from getopt is + 1, not 0. + (command_variables): New type and variable. + (decode_switches, decode_env_switches): After making a variable + definition, record the struct variable pointer in the + command_variables chain. + (define_makeflags): If ALL, write variable definitions for + command_variables. + + * main.c (other_args): Variable removed. + (goals, lastgoal): New static variables (moved from auto in main). + (main): Don't process OTHER_ARGS at all. + Don't set variable MAKEOVERRIDES at all; define MAKE to just + $(MAKE_COMMAND). + (init_switches): Prepend a - {return in order} instead of a + + {require order}. + (decode_switches): Don't set OTHER_ARGS at all. + Grok '\0' return from getopt_long as non-option argument; try + variable definition and (if !ENV) enter goal targets here. + (decode_env_switches): Use allocated_variable_expand to store value. + Use find_next_token to simplify word-splitting loop. Don't + prepend a dash to uninterpreted value. Instead, if split into + only one word, try variable definition and failing that prepend a + dash to the word and pass it to decode_switches as a single arg. + +Wed Sep 7 03:02:46 1994 Roland McGrath + + * remake.c (notice_finished_file): Only recheck modtimes if + FILE->command_state was cs_running on entry (meaning the commands + actually just ran). + (update_file_1): Whenever we set FILE->update_status, call + notice_finished_file instead of just set_command_state. + * job.c (start_job_command): Whenever we set + CHILD->file->update_status, call notice_finished_file instead of + just set_command_state. + +Tue Sep 6 19:13:54 1994 Roland McGrath + + * default.c: Add missing ". + + * job.c: Changed all assignments of command_state members to calls + to set_command_state. + * remake.c: Likewise. + * file.c (set_command_state): New function. + * file.h: Declare set_command_state. + + * main.c (init_switches): Put a + first in options. + +Mon Jul 25 18:07:46 1994 Roland McGrath + + Merge MSDOS/GO32 port from DJ Delorie . + * vpath.c: Changed all uses of ':' to PATH_SEPARATOR_CHAR. + * main.c (directory_before_chdir): New variable, moved out of main + (was local). + (main) [__MSDOS__]: Look for \ or : to delimit last component of + PROGRAM. Don't frob ARGV[0] before setting MAKE_COMMAND variable. + (die): Change back to `directory_before_chdir' before dying. + * make.h (PATH_SEPARATOR_CHAR): New macro; differing defns for + [__MSDOS__] and not. + * job.c [__MSDOS__]: Include . + [__MSDOS__] (dos_pid, dos_status, dos_bname, dos_bename, + dos_batch_file): New variables. + (reap_children) [__MSDOS__]: Don't call wait; just examine those vars. + (unblock_sigs) [__MSDOS__]: Do nothing. + (start_job_command) [__MSDOS__]: Use spawnvpe instead of vfork & exec. + (load_too_high) [__MSDOS__]: Always return true. + (search_path) [__MSDOS__]: Check for : or / in FILE to punt. + Use PATH_SEPARATOR_CHAR instead of ':'. + (construct_command_argv_internal) [__MSDOS__]: Wholly different + values for sh_chars and sh_cmds. Wholly new code to handle shell + scripts. + * function.c (expand_function: `shell') [__MSDOS__]: Wholly new + implementation. + * dir.c [__MSDOS__] (dosify): New function. + (dir_contents_file_exists_p) [__MSDOS__]: Call it on FILENAME and + process the result instead of FILENAME itself. + (file_impossible_p) [__MSDOS__]: Likewise. + * default.c [__MSDOS__]: Define GCC_IS_NATIVE. + (default_suffix_rules) [__MSDOS__]: Use `y_tab.c' instead of `y.tab.c'. + (default_variables) [GCC_IS_NATIVE]: Set CC and CXX to `gcc', YACC to + `bison -y', and LEX to `flex'. + * configure.bat, configh.dos: New files. + * commands.c (fatal_error_signal) [__MSDOS__]: Just remove + intermediates and exit. + + * commands.c (set_file_variables): Add parens in length + computation in .SUFFIXES dep loop to quiet compiler warning. From + Jim Meyering. + + * read.c (read_makefile): Free FILENAME if we allocated it. From + Jim Meyering. + +Mon Jul 4 17:47:08 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * misc.c (safe_stat): New function, EINTR-safe wrapper around stat. + * vpath.c (selective_vpath_search): Use safe_stat in place of stat. + * read.c (construct_include_path): Use safe_stat in place of stat. + * job.c (search_path): Use safe_stat in place of stat. + * dir.c (find_directory): Use safe_stat in place of stat. + * commands.c (delete_target): Use safe_stat in place of stat. + * arscan.c (ar_member_touch) [EINTR]: Do EINTR looping around fstat. + * remake.c (name_mtime): Use safe_stat in place of stat. + (touch_file) [EINTR]: Do EINTR looping around fstat. + +Fri Jun 24 05:40:24 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * read.c (read_makefile): Check for a shell command first, and + then strip leading tabs before further checking if it's not a + shell command line. + + * make.h [__arm]: Undefine POSIX. + [!__GNU_LIBRARY__ && !POSIX && !_POSIX_VERSION]: Don't declare system + functions that return int. + + * job.c (construct_command_argv_internal): After swallowing a + backslash-newline combination, if INSTRING is set goto string_char + (new label) for normal INSTRING handling code. + +Sat Jun 4 01:11:20 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * configure.in: Don't check for sys_siglist and _sys_siglist with + AC_HAVE_FUNCS. Instead use two AC_COMPILE_CHECKs. + +Mon May 23 18:20:38 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.71.1 released. + + * make.h [!__GNU_LIBRARY__ && !POSIX]: Also test #ifndef + _POSIX_VERSION for these declarations. + + * misc.c [GETLOADAVG_PRIVILEGED] [POSIX]: Remove bogus #ifndefs + around #undefs of HAVE_SETREUID and HAVE_SETREGID. + +Sat May 21 16:26:38 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.71 released. + + * misc.c [GETLOADAVG_PRIVILEGED] [POSIX]: Don't test [HAVE_SETUID] + and [HAVE_SETGID]. Every system has those, and configure doesn't + check for them. + + * make.h [_POSIX_VERSION]: Don't #define POSIX #ifdef ultrix. + + * compatMakefile (loadavg): Depend on and use loadavg.c instead of + getloadavg.c. + (loadavg.c): Link or copy it from getloadavg.c. + (distclean): Remove loadavg.c. + +Mon May 16 22:59:04 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.70.4. + + * misc.c [GETLOADAVG_PRIVILEGED] [! POSIX]: Undefine HAVE_SETEUID + and HAVE_SETEGID. + + * default.c (default_terminal_rules): In SCCS rules, put + $(SCCS_OUTPUT_OPTION) before $<. On some systems -G is grokked + only before the file name. + * configure.in (SCCS_GET_MINUS_G check): Put -G flag before file name. + +Tue May 10 16:27:38 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * job.c (construct_command_argv_internal): Swallow + backslash-newline combinations inside '' strings too. + +Thu May 5 04:15:10 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * read.c (do_define): Call collapse_continuations on each line + before all else. + +Mon Apr 25 19:32:02 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * job.c (construct_command_argv_internal): Notice newline inside + '' string when RESTP is non-null. + +Fri Apr 22 17:33:30 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.70.3. + + * remake.c (update_goal_chain): Reset FILE to G->file after the + double-colon loop so it is never null for following code. + + * read.c (read_makefile): Fix `override define' parsing to skip + whitespace after `define' properly. + + * compatMakefile (srcdir): Define as @srcdir@; don't reference + $(VPATH). + (glob/Makefile): New target. + +Thu Apr 21 16:16:55 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.70.2. + + * misc.c (remove_comments): Use find_char_unquote. + * make.h (find_char_unquote): Declare it. + * read.c (find_char_unquote): New function, generalized from + find_percent. + (find_percent, find_semicolon, parse_file_seq): Use that. + +Wed Apr 20 18:42:39 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * implicit.c (pattern_search): Always allocate new storage for + FILE->stem. It is not safe to store STEM's address because it + might be auto storage. + + * configure.in: Check for seteuid and setegid. + * misc.c [HAVE_SETEUID]: Declare seteuid. + [HAVE_SETEGID]: Declare setegid. + (make_access, user_access) [HAVE_SETEUID]: Use seteuid. + [HAVE_SETEGID]: Use setegid. + + * remake.c (update_goal_chain): Set STATUS to FILE->update_status, + to preserve whether it's 2 for error or 1 for -q trigger. When + STATUS gets nonzero and -q is set, always stop immediately. + * main.c (main, decode_switches): Die with 2 for errors. + (main): Accept 2 return from update_goal_chain and die with that. + * misc.c (fatal, makefile_fatal): Die with 2; 1 is reserved for -q + answer. + * job.c (reap_children): Die with 2 for error. + (start_job_command): Set update_status to 2 for error. Set it to + 1 when we would run a command and question_flag is set. + + * read.c (read_makefile): Don't mark makefiles as precious. Just + like other targets, they can be left inconsistent and in need of + remaking by aborted commands. + + * read.c (read_makefile): Write no error msg for -include file. + +Tue Apr 5 05:22:19 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * commands.c (fatal_error_signal): Don't unblock signals. + + * file.h (struct file): Change member `double_colon' from flag to + `struct file *'. + * read.c (record_files): Set double_colon pointer instead of flag. + * main.c (main): When disqualifying makefiles for updating, use + double_colon pointer to find all entries for a file. + * file.c (enter_file): If there is already a double-colon entry + for the file, set NEW->double_colon to that pointer. + (file_hash_enter): Use FILE->double_colon to find all entries to + set name. + * remake.c (update_goal_chain): Do inner loop on double-colon entries. + (update_file): Use FILE->double_colon pointer to find all entries. + (f_mtime): Likewise. + (notice_finished_file): Propagate mtime change to all entries. + + * variable.c (try_variable_definition): Return after abort. + +Fri Apr 1 18:44:15 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * read.c (read_makefile): Remove unused variable. + (parse_file_seq): When removing an elt that is just `)', properly + fix up the previous elt's next pointer. + +Mon Mar 28 18:31:49 1994 Roland McGrath (roland@mole.gnu.ai.mit.edu) + + * configure.in: Do AC_SET_MAKE. + * GNUmakefile (Makefile.in): Edit MAKE assignment into @SET_MAKE@. + +Fri Mar 4 00:02:32 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * function.c (subst_expand): If BY_WORD or SUFFIX_ONLY is set and + the search string is the empty string, find a match at the end of + each word (using end_of_token in place of sindex). + + * misc.c (end_of_token): Don't treat backslashes specially; you + can no longer escape blanks with backslashes in export, unexport, + and vpath. This was never documented anyway. + +Thu Mar 3 23:53:46 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * read.c (read_makefile): Variable name for `define' is not just + first token; use whole rest of line and strip trailing blanks. + +Wed Feb 16 16:03:45 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.70.1. + + * read.c (read_makefile): Add -d msg stating args. + + * read.c (read_makefile): Use isspace to skip over leading + whitespace, and explicitly avoid skipping over tabs. Don't want + to skip just spaces though; formfeeds et al should be skipped. + + * default.c (default_variables) [__hpux]: Add f in ARFLAGS. + + * arscan.c (ar_name_equal) [__hpux]: Subtract 2 instead of 1 from + sizeof ar_name for max length to compare. + + * misc.c [GETLOADAVG_PRIVILEGED] [POSIX]: Undefine HAVE_SETREUID + #ifdef HAVE_SETUID; likewise HAVE_SETREGID and HAVE_SETGID. + + * main.c (main): Call user_access after setting `program', in case + it needs to use it in an error message. + + * read.c (read_makefile): Ignore an empty line starting with a tab. + +Thu Feb 10 21:45:31 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * configure.in (AC_SYS_SIGLIST_DECLARED): Use this instead of + AC_COMPILE_CHECK that is now its contents. + +Fri Feb 4 16:28:54 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * make.h: #undef strerror after #include . + [! ANSI_STRING]: Declare strerror. + +Thu Feb 3 02:21:22 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * misc.c (strerror): #undef any macro before function definition. + +Mon Jan 31 19:07:23 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * variable.c (try_variable_definition): Calculate BEG before loop + to strip blanks by decrementing END. Don't decr END to before BEG. + + * read.c (read_makefile): Skip over leading space characters, but + not tabs, after removing continuations and comments (it used to + use isspace). + +Tue Jan 25 16:45:05 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * variable.c (define_automatic_variables): In $(@D) et al, use + patsubst to remove trailing slash. + + * commands.c (delete_target): New function, broken out of + delete_child_targets. Check for archive members and give special msg. + (delete_child_targets): Use delete_target. + +Mon Jan 17 17:03:22 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * default.c (default_suffix_rules): Use $(TEXI2DVI_FLAGS) in + texi2dvi rules. Use $(MAKEINFO_FLAGS) in makeinfo rules. + +Tue Jan 11 19:29:55 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * GNUmakefile (tarfiles): Omit make-doc. + (make-$(version).tar): Include make.info*. + +Fri Jan 7 16:27:00 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * compatMakefile (configure, config.h.in): Comment out rules. + +Thu Jan 6 18:08:08 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * compatMakefile (binprefix, manprefix): New variables. + (instname): Variable removed. + (install): Use $({bin,man}prefix)make in place of $(instname). + File targets likewised renamed. + +Mon Jan 3 17:50:25 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.70 released. + +Thu Dec 23 14:46:54 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.69.3. + + * read.c (parse_file_seq): Inside multi-word archive ref + translation loop, check NEW1==0 at end and break out of the loop. + + * GNUmakefile (make-$(version).tar): Distribute install.sh. + * install.sh: New file. + + * configure.in (SCCS_GET_MINUS_G check): Put redirection for admin + cmds outside subshell parens, to avoid "command not found" msgs + from the shell. + +Wed Dec 22 17:00:43 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * configure.in (SCCS_GET_MINUS_G check): Put -G flag last in get cmd. + Redirect output & error from get to /dev/null. + Fix reversed sense of test. + +Fri Dec 17 15:31:36 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * configure.in (SCCS_GET_MINUS_G check): Use parens instead of + braces inside if condition command; some shells lose. + +Thu Dec 16 15:10:23 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.69.2. + + * arscan.c [M_UNIX]: Move #undef M_XENIX for PORTAR stuff. + (PORTAR) [M_XENIX]: Define to 0 instead of 1. + + * main.c (define_makeflags): Only export MAKEFLAGS if !ALL. + +Wed Dec 15 17:47:48 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * main.c (main): Cast result of pointer arith to unsigned int + before passing to define_variable for envars. Matters when + sizeof(unsigned)!=sizeof(ptrdiff_t). + +Tue Dec 14 14:21:16 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * configure.in: Add new check for SCCS_GET_MINUS_G. + * config.h.in: Add #undef SCCS_GET_MINUS_G. + * default.c (default_terminal_rules): Use `$(SCCS_OUTPUT_OPTION)' in + place of `-G $@' in SCCS commands. + (default_variables) [SCCS_GET_MINUS_G]: Define SCCS_OUTPUT_OPTION + to "-G$@". + + * configure.in (AC_OUTPUT): Put touch stamp-config in second arg + (so it goes in config.status), rather than afterward. + + * ar.c (ar_member_date): Don't call enter_file on the archive file + if it doesn't exist (by file_exists_p). + + * compatMakefile ($(infodir)/make.info): Replace `$$d/foo.info' + with `$$dir/make.info' in install-info invocation (oops). + + * vpath.c (construct_vpath_list): Only set LASTPATH set PATH when + we do not unlink and free PATH. + + * file.c (print_file_data_base): Fix inverted calculation for + average files per hash bucket. + + * read.c (readline): When we see a NUL, give only a warning and + synthesize a newline to terminate the building line (used to + fatal). Move fgets call into the loop condition, and after the + loop test ferror (used to test !feof in the loop). + +Fri Dec 3 16:40:31 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * configure.in: Check for strerror in AC_HAVE_FUNCS. + +Thu Dec 2 15:37:50 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + Differentiate different flavors of missing makefile error msgs, + removing gratuitous `fopen: ' and giving caller for included makefiles. + * misc.c [! HAVE_STRERROR]: Define our own strerror here. + (perror_with_name, pfatal_with_name): Use strerror instead of + replicating its functionality. + * read.c (read_makefile): Return int instead of void. + (read_all_makefiles, read_makefile): Change callers to notice zero + return and give error msg. + +Thu Nov 11 11:47:36 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.69.1. + + * default.c: Put `-G $@' before $< in SCCS cmds. + +Wed Nov 10 06:06:14 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * read.c (read_makefile): After trying a variable defn, notice if + the line begins with a tab, and diagnose an error. + +Sun Nov 7 08:07:37 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.69. + +Wed Nov 3 06:54:33 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.68.10. + + * implicit.c (try_implicit_rule): Look for a normal rule before an + archive rule. + +Fri Oct 29 16:45:28 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * function.c (expand_function: `sort'): Double NWORDS when it + overflows, instead of adding five. + + * compatMakefile (clean): Remove loadavg. + +Wed Oct 27 17:58:33 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.68.9. + + * file.h (NEW_MTIME): Define new macro. + * main.c (main): Set time of NEW_FILES to NEW_MTIME, not to + current time returned from system. Removed variable NOW. + * remake.c (notice_finished_file): Use NEW_MTIME in place of + current time here too. + +Tue Oct 26 19:45:35 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.68.8. + + * remake.c (update_file_1): Don't clear MUST_MAKE when FILE has no + cmds and !DEPS_CHANGED unless also !NOEXIST. + +Mon Oct 25 15:25:21 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * read.c (parse_file_seq): When converting multi-word archive + refs, ignore a word beginning with a '('. + +Fri Oct 22 02:53:38 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * configure.in: Check for sys/timeb.h. + * make.h [HAVE_SYS_TIMEB_H]: Test this before including it. + +Thu Oct 21 16:48:17 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.68.7. + + * rule.c (convert_suffix_rule): New local TARGPERCENT. Set it to + TARGNAME+1 for "(%.o)", to TARGNAME for "%.?". Use it in place of + TARGNAME to initialize PERCENTS[0]. + +Mon Oct 18 06:49:35 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * configure.in: Use AC_HAVE_HEADERS(unistd.h) instead of AC_UNISTD_H. + Remove AC_USG; it is no longer used. + + * file.c (print_file): New function, broken out of + print_file_data_base. + (print_file_data_base): Call it. + * rule.c (print_rule): New function, broken out of + print_rule_data_base. + (print_rule_data_base): Call it. + +Thu Oct 14 14:54:03 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * default.c (install_default_suffix_rules): New function, broken + out of install_default_implicit_rules. + (install_default_implicit_rules): Move suffix rule code there. + * make.h: Declare install_default_suffix_rules. + * main.c (main): Call install_default_suffix_rules before reading + makefiles. Move convert_to_pattern call before + install_default_implicit_rules. + + * job.h (struct child): Make `pid' member type `pid_t' instead of + `int'. + + * compatMakefile (RANLIB): New variable, set by configure. + (glob/libglob.a): Pass RANLIB value down to submake. + + Fixes for SCO 3.2 "devsys 4.2" from pss@tfn.com (Peter Salvitti). + * make.h: Include before for SCO lossage. + * job.c [! getdtablesize] [! HAVE_GETDTABLESIZE]: If NOFILE is not + defined but NOFILES_MAX is, define it to be that. + +Mon Oct 11 19:47:33 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * GNUmakefile (make-$(version).tar): Depend on acconfig.h, so it + is distributed. + +Sun Oct 3 15:15:33 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * default.c (default_terminal_rules): Add `-G $@' to SCCS get cmds. + +Tue Sep 28 14:18:20 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * job.c (construct_command_argv_internal): Add ^ to SH_CHARS; it + is another symbol for | in some shells. + * main.c (main): Add it to CMD_DEFS quoting list as well. + +Mon Sep 20 18:05:24 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * job.c (construct_command_argv_internal): Remove '=' from + SH_CHARS. Only punt on '=' if it is unquoted in a word before the + first word without an unquoted '='. + + * main.c (define_makeflags): Set v_export for MAKEFLAGS. + +Fri Sep 17 00:37:18 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * remake.c (update_file_1): Use .DEFAULT cmds for phony targets. + + * make.h [_AIX && _POSIX_SOURCE]: Define POSIX. + + * commands.c (delete_child_targets): Don't delete phony files. + + * job.c (start_job_command): Set COMMANDS_RECURSE in FLAGS if we + see a `+' at the beginning of the command line. + +Thu Sep 9 17:57:14 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.68.6. + +Wed Sep 8 20:14:21 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * main.c (define_makeflags): Define MAKEFLAGS with o_file, not o_env. + +Mon Aug 30 12:31:58 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * expand.c (variable_expand): Fatal on an unterminated reference. + +Thu Aug 19 16:27:53 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.68.5. + + * variable.c (define_automatic_variables): Define new o_default + variable `MAKE_VERSION' from version_string and remote_description. + + * make.h (version_string, remote_description): Declare these here. + * main.c: Don't declare version_string. + (print_version): Don't declare remote_description. + +Wed Aug 18 15:01:24 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * read.c (read_makefile): Free space pointed to by CONDITIONALS + before restoring the old pointer. + +Mon Aug 16 17:33:36 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * compatMakefile ($(objs)): Depend on config.h. + + * GNUmakefile (build.sh.in): Depend on compatMakefile. + + * configure.in: Touch stamp-config after AC_OUTPUT. + +Fri Aug 13 16:04:22 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.68.4. + +Thu Aug 12 17:18:57 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * make.h: Include instead of "config.h". + +Wed Aug 11 02:35:25 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * main.c (main): Make all variables interned from ENVP be v_export. + * variable.c (try_variable_definition): In v_default case, don't + check for an o_file variable that `getenv' finds. + + * job.c (reap_children): New local variable ANY_LOCAL; set it + while setting ANY_REMOTE. If !ANY_LOCAL, don't wait for local kids. + + * main.c (main): Don't call decode_env_switches on MFLAGS. DOC THIS. + + * function.c (expand_function): #if 0 out freeing of ENVP since it + is environ. + +Mon Aug 9 17:37:20 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.68.3. + + * remote-stub.c (remote_status): Set errno to ECHILD before return. + * job.c (reap_children): Scan the chain for remote children and + never call remote_status if there are none. + + * function.c (expand_function: `shell'): #if 0 out calling + target_environment; just set ENVP to environ instead. + + * job.c (reap_children): Check for negative return from + remote_status and fatal for it. + When blocking local child wait returns 0, then try a blocking call + to remote_status. + +Tue Aug 3 00:19:00 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * compatMakefile (clean): Delete make.info* and make.dvi here. + (distclean): Not here. + + * dep.h (RM_*): Use #defines instead of enum to avoid lossage from + compilers that don't like enum values used as ints. + +Mon Aug 2 16:46:34 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * compatMakefile (loadavg): Add $(LOADLIBES). + +Sun Aug 1 16:01:15 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.68.2. + + * compatMakefile (loadavg, check-loadavg): New targets. + (check): Depend on check-loadavg. + + * compatMakefile (glob/libglob.a): Depend on config.h. + + * misc.c (log_access): Write to stderr instead of stdout. + +Fri Jul 30 00:07:02 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.68.1. + +Thu Jul 29 23:26:40 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * configure.in (SYS_SIGLIST_DECLARED): In test program include + #ifdef HAVE_UNISTD_H. + + * compatMakefile (.PHONY): Put after `all' et al. + + * configure.in: Add AC_IRIX_SUN. + +Wed Jul 28 17:41:12 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.68. + +Mon Jul 26 14:36:49 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.67.8. + +Sun Jul 25 22:09:08 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.67.7. + + * compatMakefile ($(infodir)/make.info): Don't use $(instname). + Run install-info script if present. + +Fri Jul 23 16:03:50 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * make.h [STAT_MACROS_BROKEN]: Test this instead of [uts]. + + * configure.in: Add AC_STAT_MACROS_BROKEN. + +Wed Jul 14 18:48:11 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.67.6. + + * read.c (read_makefile): Recognize directive `-include', like + `include' but sets RM_DONTCARE flag. + + * variable.c (target_environment): If FILE is nil, use + current_variable_set_list in place of FILE->variables. + * function.c (expand_function: `shell'): Get an environment for + the child from target_environment instead of using environ. + + * dep.h: Declare read_all_makefiles here. + (RM_*): Define new enum constants. + * read.c (read_makefile): Second arg is FLAGS instead of TYPE. + Treat it as a bit mask containing RM_*. + (read_all_makefiles): For default makefiles, set D->changed to + RM_DONTCARE instead of 1. + * main.c: Don't declare read_all_makefiles here. + (main): Check `changed' member of read_makefiles elts for RM_* + flags instead of specific integer values. + +Mon Jul 12 22:42:17 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * make.h [sequent && i386]: #undef POSIX. From trost@cse.ogi.edu. + +Thu Jul 8 19:51:23 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * vpath.c (construct_vpath_list): If ELEM is zero 0, free PATTERN + as well as VPATH. + (build_vpath_lists): Empty `vpaths' around construct_vpath_list + call for $(VPATH). Expand $(strip $(VPATH)), not just $(VPATH). + + * rule.c (convert_suffix_rule): Use alloca instead of xmalloc for + PERCENTS, whose storage is not consumed by create_pattern_rule. + + * make.h [__mips && _SYSTYPE_SVR3]: #undef POSIX. + +Wed Jun 30 18:11:40 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.67.5. + + * rule.c (max_pattern_targets): New variable. + (count_implicit_rule_limits): Compute its value. + * rule.h: Declare it. + * implicit.c (pattern_search): Make TRYRULES max_target_patterns + times bigger. Move adding new TRYRULES elt inside the inner + targets loop, so each matching target gets its own elt in MATCHES + and CHECKED_LASTSLASH. + + * file.c (remove_intermediates): If SIG!=0 say `intermediate file' + instead of just `file' in error msg. + +Fri Jun 25 14:55:15 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * job.c (construct_command_argv): Turn off + --warn-undefined-variables around expansion of SHELL and IFS. + * read.c (tilde_expand): Likewise for HOME. + (read_all_makefiles): Likewise for MAKEFILES. + * vpath.c (build_vpath_lists): Likewise for VPATH. + + * main.c (warn_undefined_variables_flag): New flag variable. + (switches): Add --warn-undefined-variables. + * make.h (warn_undefined_variables_flag): Declare it. + * expand.c (warn_undefined): New function. + (reference_variable): Call it if the variable is undefined. + (variable_expand): In substitution ref, call warn_undefined if the + variable is undefined. + + * default.c (default_pattern_rules): Add `%.c: %.w %.ch' and + `%.tex: %.w %.ch' rules. + (default_suffix_rules: .w.c, .w.tex): Pass three args: $< - $@. + (default_suffixes): Add `.ch'. + +Mon Jun 21 17:55:39 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * default.c (default_suffixes): Replace `.cweb' with `.w'. + (default_suffix_rules): Rename `.cweb.c' and `.cweb.tex' to `.w.c' + and `.w.tex'. + +Fri Jun 11 14:42:09 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * compatMakefile ($(bindir)/$(instname)): Add missing backslash. + +Thu Jun 10 18:14:08 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.67.4. + + * read.c (multi_glob): Don't free OLD and OLD->name in the + FOUND!=0 fork. Use new block-local variable F instead of + clobbering OLD. + + * ar.c (glob_pattern_p): New function, snarfed from glob/glob.c. + (ar_glob): Call it; return nil immediately if MEMBER_PATTERN + contains no metacharacters. + +Wed Jun 9 16:25:35 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * ar.c (ar_glob{_match,_alphacompare}): New function. + + * dep.h [! NO_ARCHIVES]: Declare it. + * read.c (multi_glob) [! NO_ARCHIVES]: Use it on archive member elts. + + * read.c (read_makefile): Pass flag (1) to parse_file_seq, not to + multi_glob (which doesn't take a 3rd arg). + * rule.c (install_pattern_rule): Likewise. + * default.c (set_default_suffixes): Here too. + * function.c (string_glob): Don't pass gratuitous arg to multi_glob. + + * read.c (parse_file_seq) [! NO_ARCHIVES]: Add post-processing + loop to translate archive refs "lib(a b)" into "lib(a) lib(b)". + +Mon Jun 7 19:26:51 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * compatMakefile (installdirs): Actually pass directory names. + ($(bindir)/$(instname)): Test chgrp&&chmod exit status with `if'; + if it fails, echo a warning msg, but don't make the rule fail. + + * read.c (tilde_expand): New function, broken out of tilde_expand. + (multi_glob): Call it. + (construct_include_path): Expand ~ in directory names. + * dep.h: Declare tilde_expand. + * main.c (enter_command_line_file): Expand ~ at the start of NAME. + (main): Expand ~ in -C args. + * read.c (read_makefile): Expand ~ in FILENAME unless TYPE==2. + +Fri Jun 4 13:34:47 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * main.c (decode_env_switches): Use xmalloc instead of alloca for ARGS. + + * main.c (main): Put result of alloca in temporary variable with + simple assignment, to make SGI compiler happy. + +Thu Jun 3 20:15:46 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.67.3. + + * main.c (main): Before re-execing, remove intermediate files, and + print the data base under -p. Sexier debugging message. + + * implicit.c (pattern_search): Allocate an extra copy of the name + of a winning intermediate file when putting it in FOUND_FILES. + +Wed Jun 2 16:38:08 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * read.c (read_makefile): Pass flag (1) to parse_file_seq, not to + multi_glob (which doesn't take a 3rd arg). + + * dir.c (dir_contents_file_exists_p): When reading dirents, ignore + chars within D_NAMLEN that are NULs. + + * main.c (decode_switches): Don't savestring ARGV[0] to put it + into `other_args'. + For string switch, don't savestring `optarg'. + (main): Don't free elts of makefiles->list that are "-". + Use alloca'd rather than savestring'd storage for elts of + makefiles->list that are temporary file names. + * read.c (read_all_makefiles): Don't free *MAKEFILES. + * file.c (enter_file): Don't strip `./'s. + * main.c (enter_command_line_file): New function. + (main): Use it in place of enter_file for command-line goals from + other_files, and for old_files and new_files. + +Mon May 31 18:41:40 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.67.2. + + * compatMakefile (.SUFFIXES): Add .info. + ($(infodir)/$(instname).info): Find make.info* in cwd if there, + else in $srcdir. Use basename to remove dir name from installed name. + +Thu May 27 17:35:02 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * implicit.c (pattern_search): When interning FOUND_FILES, try + lookup_file first; if found, free the storage for our copy of the name. + +Wed May 26 14:31:20 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.67.1. + + * main.c (decode_switches): In usage msg, write `--switch=ARG' or + `--switch[=OPTARG]' rather than `--switch ARG' or `--switch [ARG]'. + +Mon May 24 16:17:31 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * rule.c (convert_suffix_rule): New function. + (convert_to_pattern): Use it instead of doing all the work here + several times. + For target suffix `.a', generate both the archive magic rule and + the normal rule. + + * compatMakefile (distclean): Remove stamp-config. + +Sat May 22 16:15:18 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.67. + + * file.c (remove_intermediates): Don't write extra space after `rm'. + + * main.c (struct command_switch.type): Remove `usage_and_exit'. + (print_usage_flag): New variable. + (switches: --help): Make type `flag', to set print_usage_flag. + (init_switches): Remove `usage_and_exit' case. + (decode_switches): Likewise. + (decode_switches): Print usage if print_usage_flag is set. + When printing usage, die with status of BAD. + (main): Die with 0 if print_version_flag. + +Fri May 21 16:09:28 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.66. + +Wed May 19 21:30:44 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * compatMakefile (installdirs): New target. + (install): Depend on it. + +Sun May 16 20:15:07 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.65.2. + +Fri May 14 16:40:09 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * vpath.c (construct_vpath_list): In removal loop for DIRPATH==0, + set LASTPATH to PATH, not NEXT. + + * dir.c (read_dirstream): Break out of loop after incrementing + DS->buckets such that it reaches DIRFILE_BUCKETS; avoid trying to + dereference DS->contents->files[DIRFILE_BUCKETS]. + + * read.c (read_makefile): Clear no_targets after reading a + targetful rule line. + + * main.c (main): If print_version_flag is set, exit after printing + the version. + (switches): Change --version docstring to say it exits. + + * make.h [butterfly]: #undef POSIX. + +Wed May 12 15:20:21 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.65.1. + + * arscan.c (ar_scan) [! AIAMAG]: Don't declare LONG_NAME. + [AIAMAG]: Pass TRUNCATE flag arg to (*FUNCTION), always zero. + + * function.c (handle_function): Use fatal instead of + makefile_fatal when reading_filename is nil. + + * configure.in: Add AC_GETGROUPS_T. + * job.c (search_path): Use GETGROUPS_T in place of gid_t. + +Sun May 9 15:41:25 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.65. + +Fri May 7 18:34:56 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * function.c (handle_function): Fatal for unmatched paren. + +Thu May 6 16:13:41 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.64.3. + + * commands.c (handling_fatal_signal): New variable. + (fatal_error_signal): Set it. + * job.c (reap_children): Avoid nonreentrant operations if that is set. + * make.h: Declare handling_fatal_signal. + + * expand.c (reference_variable): New function, snippet of code + broken out of simple-reference case of variable_expand. + (variable_expand): Use it for simple refs. + (variable_expand): When checking for a computed variable name, + notice a colon that comes before the final CLOSEPAREN. Expand + only up to the colon, and then replace the pending text with a + copy containing the expanded name and fall through to subst ref + handling. + (variable_expand): Don't bother expanding the name if a colon + appears before the first $. + (expand_argument): Use alloca instead of savestring. + (variable_expand): For subst ref, expand both sides of = before + passing to [pat]subst_expand. Use find_percent instead of lindex + to check the lhs for a %. + +Wed May 5 14:45:52 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.64.2. + +Mon May 3 17:00:32 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * arscan.c (ar_name_equal) [AIAMAG]: Abort if TRUNCATED is nonzero. + + * read.c (read_makefile): Pass extra arg of 1 to parse_file_seq, + not to multi_glob. + +Thu Apr 29 19:47:33 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.64.1. + + * arscan.c (ar_scan): New local flag var LONG_NAME. Set it when + we read the member name in any of the fashions that allow it to be + arbitrarily long. Pass its negation to FUNCTION. + (describe_member): Take TRUNCATED from ar_scan and print it. + (ar_name_equal): Take new arg TRUNCATED; if nonzero, compare only + the first sizeof (struct ar_hdr.ar_name) chars. + (ar_member_pos): Take TRUNCATED from ar_scan, pass to ar_name_equal. + * ar.c (ar_member_date_1): Likewise. + +Wed Apr 28 21:18:22 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * job.c (reap_children): Before calling start_job_command to start + the next command line, reset C->remote by calling start_remote_job_p. + +Mon Apr 26 15:56:15 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * arscan.c (ar_scan): New local var NAMEMAP. + In loop, rename NAME to NAMEBUF; new var NAME is a pointer; new + flag IS_NAMEMAP. When extracting the member name, always put a + null at its end first. If the name is "//" or "/ARFILENAMES", set + IS_NAMEMAP. If we have already read in NAMEMAP, and NAME looks + like " /N", get full name from NAMEMAP+N. + Else if NAME looks like "#1/N", read N chars from the + elt data to be the full name. At end of loop, if IS_NAMEMAP, read + the elt's data into alloca'd NAMEMAP. + (ar_name_equal): #if 0 truncating code. + + * make.h: Don't declare vfork at all. It returns int anyway, + unless declared it; and we conflicted with some systems. + + * main.c (define_makeflags): If FLAGSTRING[1] is '-', define + MAKEFLAGS to all of FLAGSTRING, not &FLAGSTRING[1]. Don't want to + define it to something like "-no-print-directory". + Use %g format instead of %f for floating-valued things. + +Thu Apr 22 18:40:58 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * GNUmakefile (Makefile.in): Use a substitution ref on nolib-deps + to change remote-%.dep to remote-stub.dep. + +Wed Apr 21 15:17:54 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.64. + +Fri Apr 16 14:22:22 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * compatMakefile (install): Remove - prefix from chgrp+chmod. + + * Version 3.63.8. + +Thu Apr 15 18:24:07 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * acconfig.h: New file; contains "#undef SCCS_GET" for autoheader. + * configure.in: If /usr/sccs/get exists, define SCCS_GET to that, + else to "get". + * default.c (default_variables): Set GET to macro SCCS_GET. + + * read.c (parse_file_seq): Take extra arg STRIP; strip `./' only + if nonzero. I hope this is the last time this argument is added + or removed. + (read_makefile): Pass it 1 when parsing include file names. + Pass it 1 when parsing target file names. + Pass it 1 when parsing static pattern target pattern names. + * rule.c (install_pattern_rule): Pass it 1 when parsing rule deps. + * default.c (set_default_suffixes): Pass it 1 when parsing + default_suffixes. + * function.c (string_glob): Pass it 0 here. + +Wed Apr 14 11:32:05 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * misc.c (log_access): New function. + ({init,user,make,child}_access): Call it. + (child_access): Abort if !access_inited. + + * main.c (switches: --no-print-directory): Use 1 instead of -1 for + single-letter option. + (init_switches, decode_switches, define_makeflags): An option with + no single-letter version is no longer indicated by a value of -1; + instead a value that is !isalnum. + (init_switches): Don't put such switches into the string, only + into the long_option table. + + * make.h [!NSIG] [!_NSIG]: #define NSIG 32. + + * job.c [HAVE_WAITPID]: Remove #undef HAVE_UNION_WAIT. AIX's + bsdcc defined WIF* to use union wait. + + * main.c (struct command_switch): Change member `c' to type int. + (switches): Make const. + (decode_switches): Use `const struct command_switch *'. + (define_makeflags): Likewise. + + * default.c (default_suffix_rules): Add `-o $@' to makeinfo rules. + +Mon Apr 12 12:30:04 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.63.7. + + * configure.in (AC_HAVE_HEADERS): Check for string.h and memory.h. + Removed AC_MEMORY_H. + * make.h [USG, NeXT]: Don't test these. + [HAVE_STRING_H]: Test this to include string.h and define ANSI_STRING. + [HAVE_MEMORY_H]: Test this instead of NEED_MEMORY_H. + [! ANSI_STRING]: Put decls of bcopy et al here. + [sparc]: Don't test this for alloca.h; HAVE_ALLOCA_H is sufficient. + [HAVE_SIGSETMASK]: Test this rather than USG. + [__GNU_LIBRARY__ || POSIX]: Don't #include again. + * main.c (main): Handle SIGCHLD if defined, and SIGCLD if defined. + It doesn't hurt to do both if they are both defined, and testing + USG is useless. + * dir.c: Rationalize directory header conditionals. + * arscan.c [HAVE_FCNTL_H]: Test this rather than USG || POSIX. + + * default.c (default_suffixes): Add `.txinfo'. + (default_suffix_rules): Add `.txinfo.info' and `.txinfo.dvi' rules. + + * variable.c (try_variable_definition): Replace RECURSIVE flag + with enum FLAVOR, which can be simple, recursive, or append. + Recognize += as append flavor. Set new variable VALUE in a switch + on FLAVOR. For append flavor, prepend the variable's old value. + If the variable was previously defined recursive, set FLAVOR to + recursive; if it was defined simple, expand the new value before + appending it to the old value. Pass RECURSIVE flag to + define_variable iff FLAVOR == recursive. + + * variable.c (try_variable_definition): Use alloca and bcopy for + NAME, instead of savestring. Might as well use stack storage + since we free it immediately anyway. + +Thu Apr 8 18:04:43 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * job.c (start_waiting_jobs): Move decl of JOB outside of loop. + + * main.c (define_makeflags): Rename `struct flag' member `switch' + to `cs', which is not a reserved word. + +Wed Apr 7 15:30:51 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * job.c (new_job): Call start_waiting_jobs first thing. + (start_waiting_job): Changed return type from void to int. + Return 0 when putting the child on the waiting_jobs chain. + (start_waiting_jobs): Don't check load and job_slots here. + Always take a job off the chain and call start_waiting_job on it; + give up and return when start_waiting_job returns zero. + + * main.c (define_makeflags: struct flag): Change member `char c' to + `struct command_switch *switch'. + (ADD_FLAG): Set that to CS instead of CS->c. + If CS->c is -1, increment FLAGSLEN for the long name. + When writing out FLAGS, handle FLAGS->switch->c == -1 and write + the long name instead. + + * compatMakefile (stamp-config): New target of old config.h rule. + Touch stamp-config after running config.status. + (config.h): Just depend on stamp-config, and have empty commands. + +Mon Apr 5 20:14:02 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * job.c [HAVE_WAITPID]: #undef HAVE_UNION_WAIT. + + * configure.in (AC_HAVE_FUNCS): Check for psignal. + +Fri Apr 2 17:15:46 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * main.c (long_option_aliases): Remove "new"; it is already an + unambiguous prefix of "new-file". + +Sun Mar 28 16:57:17 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.63.6. + +Wed Mar 24 14:26:19 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * vpath.c (selective_vpath_search): When adding the + name-within-directory at the end of NAME, and we don't add a + slash, don't copy FILENAME in one char too far into NAME. + + * variable.c (define_automatic_variables): Find default_shell's + length with strlen, not numerology. + +Wed Mar 17 20:02:27 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * main.c (define_makeflags): Add the elts of a string option in + reverse order, so they come out right when reversed again. + +Fri Mar 12 15:38:45 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * compatMakefile (make.info): Use `-o make.info'. + +Thu Mar 11 14:13:00 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * compatMakefile (REMOTE): Set to @REMOTE@; change comments to + reflect new use. + (objs): Replace remote.o with remote-$(REMOTE).o. + (srcs): Replace remote.c with remote-$(REMOTE).c. + (remote.o): Rule removed. + + * configure.in (REMOTE): Subst this in Makefile et al; default "stub". + Use AC_WITH to grok --with-customs arg to set REMOTE=cstms. + * GNUmakefile (build.sh.in): Filter out remote-% from objs list. + * build.template (REMOTE): New var; set to @REMOTE@. + (objs): Add remote-${REMOTE}.o. + +Wed Mar 10 15:12:24 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.63.5. + + * implicit.c (pattern_search): Fix "dependent"->"dependency" in + "Rejecting impossible" -d msg. + + * file.c (file_hash_enter): New local vars {OLD,NEW}BUCKET. Store + mod'd values there; never mod {OLD,NEW}HASH. + +Mon Mar 8 13:32:48 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * remake.c [eta10]: Include instead of . + + * compatMakefile (VPATH): Set this to @srcdir@. + (srcdir): Set this to $(VPATH). + + * main.c (main): New local var DIRECTORY_BEFORE_CHDIR. Save in it + a copy of CURRENT_DIRECTORY after the first getcwd. Use it + instead of CURRENT_DIRECTORY when chdir'ing back before re-execing. + + * remake.c (notice_finished_file): Pass missing SEARCH arg to f_mtime. + + * read.c (read_makefile): Remove extraneous arg to parse_file_seq. + +Mon Feb 22 14:19:38 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * compatMakefile ($(infodir)/$(instname).info): Use , instead of / + as the sed delimiter char. + +Sun Feb 21 14:11:04 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.63.4. + + * rule.h (struct rule): Removed `subdir' member. + * rule.c (new_pattern_rule): No need to clear it. + (count_implicit_rule_limits): Set the `changed' flag in each dep + that refers to a nonexistent directory. No longer set rule-global + `subdir' flag with that information. + (print_rule_data_base): Don't record info on `subdir' flags. + + * implicit.c (pattern_search): Check the DEP->changed flag rather + than the (now gone) RULE->subdir flag. Also test CHECK_LASTSLASH; + if it is set, the file might exist even though the DEP->changed + flag is set. + + * rule.c (count_implicit_rule_limits): Pass "", not ".", as file + name arg to dir_file_exists_p to check for existence of directory. + + * implicit.c (pattern_search): Inside dep-finding loop, set + CHECK_LASTSLASH from the value recorded in CHECKED_LASTSLASH[I], + rather than computing it anew. + + * commands.c (set_file_variables): Must alloca space for PERCENT + and copy it, to avoid leaving the trailing `)' in the value. + + * misc.c (remove_comments): Fixed backslash-checking loop + condition to allow it to look at the first char on the line. + P2 >= LINE, not P2 > LINE. + + * compatMakefile ($(bindir)/$(instname)): Before moving $@.new to + $@, rm $@.old and mv $@ to $@.old. + + * variable.c (try_variable_definition): Take new args FILENAME and + LINENO. Fatal if the variable name is empty. + * read.c (read_makefile): Change callers. + * main.c (main): Likewise. + + * compatMakefile (group): Define to @KMEM_GROUP@, autoconf magic + that configure will replace with the group owning /dev/kmem. + +Mon Feb 8 14:26:43 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * vpath.c (vpath_search): Take second arg MTIME_PTR, pass thru to + selective_vpath_search. + (selective_vpath_search): Take second arg MTIME_PTR. + If the dir cache thinks a file exists, stat it to make sure, and + put the modtime in *MTIME_PTR. + * remake.c (library_search): Take second arg MTIME_PTR. + When we find a match, record its mtime there. + Pass MTIME_PTR through to vpath_search to do same. + (f_mtime): Pass &MTIME as new 2nd arg to {vpath,library}_search; + store it in FILE->last_mtime if set nonzero. + * implicit.c (pattern_search): Pass nil 2nd arg to vpath_search. + + * compatMakefile (remote.o): Prepend `$(srcdir)/' to `remote-*.c', + so globbing looks somewhere it will find things. + + * compatMakefile ($(infodir)/$(instname).info): Install `make.info*' + not `$(srcdir)/make.info*'; no need to use basename. + +Fri Feb 5 12:52:43 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.63.3. + + * compatMakefile (install): Add missing ;\s. + + Make -, @, and + prefixes on a pre-expanded command line affect + all lines in the expansion, not just the first. + * commands.h (struct commands): Replace `lines_recurse' member + with `lines_flags'. + (COMMANDS_{RECURSE,SILENT,NOERROR}): New macros, bits to set in + that flag byte. + * commands.c (chop_commands): Set `lines_flags' instead of + `lines_recurse'. Record not only + but also @ and - prefixes. + * remake.c (notice_finished_file): Check the COMMANDS_RECURSE bit + in FILE->cmds->lines_flags, rather than FILE->cmds->lines_recurse. + * job.c (start_job_command): Replaced RECURSIVE and NOPRINT local + var with FLAGS; initialize it to the appropriate `lines_flags' byte. + Set CHILD->noerror if the COMMANDS_NOERROR bit is set in FLAGS. + Set the COMMANDS_SILENT bit in FLAGS for a @ prefix. + + * remake.c (update_goal_chain): Set G->file to its prev after + checking for G being finished, since that check needs to examine + G->file. + + * configure.in (union wait check) [HAVE_WAITPID]: Try using + waitpid with a `union wait' STATUS arg. If waitpid and union wait + don't work together, we should not use union wait. + + * Version 3.63.2. + + * remake.c (update_goal_chain): When G->file->updated, move + G->file to its prev. We aren't finished until G->file is nil. + +Thu Feb 4 12:53:04 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * main.c (starting_directory): New global variable. + (main): Set it to cwd after doing -Cs. + (log_working_directory): Use it, rather than computing each time. + * make.h: Declare it. + + * compatMakefile (SHELL): Define to /bin/sh for losing Unix makes. + + * main.c (decode_env_switches): Allocate (1 + LEN + 1) words for + ARGV, rather than LEN words plus one byte. + +Wed Feb 3 18:13:52 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * compatMakefile ($(bindir)/$(instname)): Put - before + install_setgid command line, so its failure won't be an error. + (infodir): New variable. + (install): Depend on $(infodir)/$(instname).info. + ($(infodir)/$(instname).info): New target. + + * read.c (read_makefile): If FILENAMES is nil when we see a line + starting with a tab, don't treat it as a command. Just fall + through, rather than giving an error. + + * read.c (read_makefile): If the NO_TARGETS flag is set when we see a + command line, don't clear it before continuing. We want + subsequent command lines to be ignored as well. + + * job.c (new_job): Before expanding each command line, collapse + backslash-newline combinations that are inside var or fn references. + +Mon Feb 1 16:00:13 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * compatMakefile (exec_prefix): Default to $(prefix), not /usr/local. + + * compatMakefile (make.info): Pass -I$(srcdir) to makeinfo. + + * job.c [POSIX] (unblock_sigs): Made global. + [!POSIX] (unblock_sigs): Move defns to job.h. + * job.h [POSIX] (unblock_sigs): Declare. + +Sun Jan 31 19:11:05 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * read.c (read_makefile): In vpath parsing, after finding the + pattern token, take entire rest of line as the search path, not + just the next token. + + * compatMakefile (remote.o): Depend on remote-*.c. + +Thu Jan 28 16:40:29 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * commands.c (set_file_variables): Don't define any F or D versions. + * variable.c (define_automatic_variables): Define them here as + recursively-expanded variables that use the dir and notdir funcs. + + * variable.c (target_environment): In v_default case, don't export + o_default or o_automatic variables. + + * configure.in (union wait check): Remove ` and ' inside C code; + they confuse the shell script. + +Mon Jan 25 13:10:42 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.63.1. + + * vpath.c (construct_vpath_list): When skipping further processing + of an elt that is ".", don't also skip the code that pushes P past + the next separator. + + * compatMakefile (distclean): Don't remove make-*. + + * configure.in (HAVE_UNION_WAIT): Try to use WEXITSTATUS if it's + defined. If one cannot use WEXITSTATUS with a `union wait' + argument, we don't want to believe the system has `union wait' at all. + + * remake.c (update_file): Do nothing to print "up to date" msgs. + (update_goal_chain): Do it here instead. + Use the `changed' flag of each goal's `struct dep' to keep track + of whether files_remade (now commands_started) changed around a + call to update_file for that goal. + When a goal is finished, and its file's update_status is zero (i.e., + success or nothing done), test the `changed' flag and give an "up + to date" msg iff it is clear. + * make.h (files_remade): Renamed to commands_started. + * remake.c: Changed defn. + (update_goal_chain): Changed uses. + * job.c (start_job_command): Increment commands_started here. + (reap_children): Not here. + + * remake.c (update_goal_chain): Don't do anything with files' + `prev' members. update_file now completely handles this. + + * variable.c (target_environment): Don't expand recursive + variables if they came from the environment. + + * main.c (define_makeflags): For flags with omitted optional args, + store {"", 0} with ADD_FLAG. When constructing FLAGSTRING, a flag + so stored cannot have more flags appended to the same word. + +Fri Jan 22 14:46:16 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * variable.c (print_variable_set): In vars/bucket calculation, + don't spuriously multiply by 100. + + * Version 3.63. + + * job.c [!HAVE_UNION_WAIT] (WTERMSIG, WCOREDUMP, WEXITSTATUS): + Don't define if already defined. + + * remake.c (update_file): Don't keep track of the command_state before + calling update_file_1. Remove local variable COMMANDS_FINISHED, + and don't test it to decide to print the "is up to date" msg. + Testing for files_remade having changed should always be sufficient. + The old method lost when we are called in the goal chain run on a + makefile, because the makefile's command_state is already + `cs_finished' from the makefile chain run. + + * misc.c [HAVE_SETRE[GU]ID]: Test these to decl setre[gu]id. + + * configure.in: Rewrote wait checking. + Use AC_HAVE_HEADERS to check for . + Use AC_HAVE_FUNCS to check for waitpid and wait3. + Use a compile check to test just for `union wait'. + * job.c: Rewrote conditionals accordingly. + [HAVE_WAITPID]: Test this only to define WAIT_NOHANG. + [HAVE_WAIT3]: Likewise. + [HAVE_UNION_WAIT]: Test this to define WAIT_T and W*. + + * configure.in: Set CFLAGS and LDFLAGS before all checks. + + * dir.c: Add static forward decls of {open,read}_dirstream. + +Thu Jan 21 17:18:00 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.62.31. + + * job.c [NGROUPS_MAX && NGROUPS_MAX==0]: #undef NGROUPS_MAX. + + * compatMakefile (CFLAGS, LDFLAGS): Set to @CFLAGS@/@LDFLAGS@. + * build.template (CFLAGS, LDFLAGS): Same here. + * configure.in: AC_SUBST(CFLAGS) and LDFLAGS. + Set them to -g if not defined in the environment. + + * remake.c (library_search): Use LIBNAME consistently, setting it + only once, to be the passed name sans `-l'. + Pass new var FILE to be modified by vpath_search. + +Mon Jan 18 14:53:54 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.62.30. + + * job.c (start_waiting_jobs): Return when job_slots_used is equal to + job_slots. + + * configure.in: Add AC_CONST for the sake of getopt. + + * read.c (read_makefile): Continue after parsing `override' + directive, rather than falling through to lossage. + Check for EOL or blank after "override define". + + * compatMakefile (.c.o, remote.o): Put $(CFLAGS) after other switches. + +Fri Jan 15 12:52:52 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.62.29. + + * main.c (define_makeflags): After writing everything into + FLAGSTRING, only back up two chars if [-1] is a dash, meaning we + just wrote " -". Always terminate the string at *P. + + * remake.c (library_search): When constructing names in std dirs, + use &(*LIB)[2] for the stem, not LIBNAME (which points at the + buffer we are writing into!). + +Thu Jan 14 13:50:06 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * read.c (read_makefile): Set IN_IGNORED_DEFINE for "override + define" when IGNORING is true. + + * compatMakefile (distclean): Remove config.status and build.sh. + +Wed Jan 13 16:01:12 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.62.28. + + * misc.c (xmalloc, xrealloc): Cast result of malloc/realloc to + (char *). + + * arscan.c (ar_scan) [AIAMAG]: Cast read arg to (char *). + + * variable.c (define_automatic_variables): Override SHELL value for + origin o_env_override as well as o_env. + + * GNUmakefile (build.sh.in): Don't replace %globobjs%. Instead, + add the names of the glob objects (w/subdir) to %objs%. + * build.template (globobjs): Removed. + Take basename of $objs before linking. + +Tue Jan 12 12:31:06 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.62.27. + + * configure.in (AC_OUTPUT): Also edit build.sh. + * build.template: New file. + * GNUmakefile (build.sh.in): New rule to create it from build.template. + (make-$(version).tar.Z): Depend on build.sh.in. + + * main.c (die): Call print_data_base if -p. + (main): Don't call it here. + + * compatMakefile (defines): Add @DEFS@. configure should turn this + into -DHAVE_CONFIG_H. + +Mon Jan 11 14:39:23 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.62.26. + + * misc.c (init_access): Surround with #ifdef GETLOADAVG_PRIVILEGED. + ({make,user,child}_access) [! GETLOADAVG_PRIVILEGED]: Make no-op. + * compatMakefile (install_setgid): New var, set by configure. + (install): Install setgid $(group) only if $(install_setgid) is true. + +Fri Jan 8 15:31:55 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * job.c (load_too_high): If getloadavg fails with errno==0, give a + message saying that load limits are not supported. + + * vpath.c (construct_vpath_list): Rewrote path deletion code to + not try to use PATH's next link after freeing PATH. + + * main.c (define_makeflags): Rewritten; now handles string-valued + option, and has no arbitrary limits. + (switches): Set `toenv' flag for -I and -v. + + * main.c (decode_env_switches): Cast return value of alloca to char *. + + * misc.c (child_access) [HAVE_SETREUID, HAVE_SETREGID]: Use + setre[gu]id in place of set[gu]id. + +Wed Jan 6 15:06:12 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * main.c (main): Define MAKEOVERRIDES, MAKE, and MAKE_COMMAND with + origin o_default. + + * make.h [POSIX]: Don't test this to use ANSI_STRING. + Testing STDC_HEADERS should be sufficient. + + * job.h: Declare start_waiting_jobs. + + * read.c (read_makefile): Add missing parens in if stmt that find + conditional directives. + + * main.c (main): Declare init_dir. + * implicit.c (pattern_search): Always use two % specs in a + DEBUGP2, and always pass two non-nil args. + Cast field width args to int. + Add missing parens in !RULE->subdir if stmt. + * function.c (expand_function, patsubst_expand): Add parens around + assignments inside `while' stmts. + * commands.c (print_commands): Cast field width args to int. + + * read.c (do_define): Cast return value of alloca to (char *). + + * main.c (init_switches): New function, broken out of decode_switches. + (decode_switches): Take new arg ENV. If set, ignore non-option + args; print no error msgs; ignore options with clear `env' flags. + (decode_env_switches): Rewritten to chop envar value into words + and pass them to decode_switches. + (switches): Set `env' flag for -I and -v. + + * dir.c (init_dir): Cast free to __glob_closedir_hook's type. + +Tue Jan 5 14:52:15 1993 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.62.25. + + * job.c [HAVE_SYS_WAIT || !USG]: Don't #include and + . interacts badly with , and + we don't need these anyway. + + * configure.in (AC_HAVE_FUNCS): Check for setre[gu]id. + * misc.c ({user,make}_access): Test #ifndef HAVE_SETRE[GU]ID, not + #ifdef POSIX || USG. SunOS 4.1 is supposedly POSIX.1 compliant, + but its set[gu]id functions aren't; its setre[gu]id functions work. + + * misc.c ({user,make,child}_access): Give name of caller in error msgs. + + * job.c (load_too_high): Say "cannot enforce load limit" in error msg. + + * configure.in: Call AC_PROG_CC. + * compatMakefile (CC): Define to @CC@ (autoconf magic). + + * compatMakefile: Add .NOEXPORT magic target. + +Mon Jan 4 17:00:03 1993 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * main.c (print_version): Updated copyright to include 93. + +Thu Dec 31 12:26:15 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * make.h [_AIX]: Don't declare alloca. + +Tue Dec 29 13:45:13 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.62.24. + + * compatMakefile (objs): Add signame.o. + (srcs): Add signame.[ch]. + + * compatMakefile (srcs): Add config.h.in. + (remote.o): Add -I. before -I$(srcdir). + +Mon Dec 28 15:51:26 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.62.23. + + * read.c (readline): Fatal when LEN==0, indicating a line starting + with a NUL. + (readline): Take new arg LINENO, for use in error msg. + (read_makefile, do_define): Pass it. + + * compatMakefile (glob/libglob.a): Pass -DHAVE_CONFIG_H in CPPFLAGS. + (.c.o): Add -I. before -I$(srcdir). + +Wed Dec 23 12:12:04 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * read.c (read_makefile): Accept and ignore a rule with no targets. + + * compatMakefile (ALLOCA_SRC): New variable. + (srcs): Include its value. + + * read.c (struct conditional): Renamed member `max_ignoring' to + `allocated'; added new member `seen_else'. + (conditional_line): Initialize seen_else flag when starting an `if...'; + set it when we see an `else'; fatal if set when we see `else'. + (read_makefile): Fatal "missing `endif'" if there are any pending + conditionals, not just if we are still ignoring. + +Tue Dec 22 15:36:28 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * compatMakefile (manext): Set to 1, not l. + ($(mandir)/$(instname).$(manext)): Use $(srcdir) for make.man in cmds. + + * file.c (file_hash_enter): Don't call uniquize_deps here. + * read.c (record_files): Likewise. + * implicit.c (pattern_search): Likewise. + * commands.c (set_file_variables): Call it only here. + + * default.c (default_variables) [__convex__]: FC=fc. + + * variable.c (target_environment): Expand the values of recursively + expanded variables when putting them into the environment. + * expand.c (recursively_expand): Made global. + * make.h (recursively_expand): Declare it. + + * remake.c (check_dep): Set FILE->command_state to cs_deps_running + when a dep's command_state is cs_running or cs_deps_running. + + * read.c (read_makefile): Changed error msg for spurious cmds to + not say "first target". + +Sun Dec 20 17:56:09 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * configure.in: Do AC_CONFIG_HEADER right after AC_INIT. + * make.h (HAVE_CONFIG_H): #include "config.h", then #define this. + * compatMakefile (config.h, configure, config.h.in): New rules. + (defines): Removed @DEFS@. + +Thu Dec 17 16:11:40 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * compatMakefile (realclean): Just depend on distclean; no cmds. + (distclean): Do what realclean did before; also remove Makefile and + config.h; don't remove configure. + (info, dvi): New targets; depend on make.{info,dvi}. + (doc): Removed target. + (MAKEINFO, TEXI2DVI): New vars. + (make.info, make.dvi): Use them instead of explicit cmds. + +Wed Dec 16 16:25:24 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * configure.in: Added fcntl.h to AC_HAVE_HEADERS. getloadavg cares. + +Wed Dec 9 15:21:01 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * main.c (long_option_aliases): Add --new-file alias for -W. + + * default.c (default_variables): Change all C++ to CXX and C++FLAGS + to CXXFLAGS. + + * read.c (do_define): Expand the variable name before using it. + + * main.c (main): Define variable "MAKE_COMMAND" to argv[0]; + define "MAKE=$(MAKE_COMMAND) $(MAKEOVERRIDES)" always. + + * remake.c (library_search): Search for libNAME.a in cwd; look in + vpath before looking in standard dirs, not after. + Changed order of std dirs to: /lib, /usr/lib, ${prefix}/lib. + +Mon Nov 23 14:57:34 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * default.c (default_pattern_rules, default_terminal_rules): Added + brackets around initializers. + + * variable.c (try_variable_definition): Don't check for LINE[0]=='\t'. + (try_variable_definition): Expand the name before defining the var. + + * job.c (init_siglist): Removed function. + Removed decl of `sys_siglist'. + * make.h [! HAVE_SYS_SIGLIST]: #include "signame.h". + [HAVE_SYS_SIGLIST && !SYS_SIGLIST_DECLARED]: Declare sys_siglist + only under these conditions. + * main.c (main): Don't declare init_siglist. + (main) [! HAVE_SYS_SIGLIST]: Call signame_init instead of init_siglist. + +Wed Nov 18 14:52:51 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * read.c (record_files): Don't try to append to FIRSTDEPS if it's + nil; instead just set it to MOREDEPS. + +Mon Nov 16 17:49:17 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * vpath.c (construct_vpath_list): Initialize P to DIRPATH before + loop that sets MAXELEM. + +Fri Nov 13 18:23:18 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.62.22. + +Thu Nov 12 15:45:31 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * job.c (start_job_command): Under -n, increment files_remade after + processing (i.e., printing) all command lines. + +Tue Nov 10 15:33:53 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * read.c (record_files): Append new deps if this rule has no + commands; prepend them to existing deps if this rule has no commands. + + * dir.c (open_dirstream): Return nil if DIR->contents->files is nil. + + * read.c (parse_file_seq): Removed last arg STRIP. Always strip `./'s. + (read_makefile): Changed callers. + * function.c (string_glob): Likewise. + * rule.c (install_pattern_rule): Likewise. + +Mon Nov 9 17:50:16 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * remake.c (files_remade): Made global. + (notice_finished_file): Don't increment files_remade here; this + function gets called in many situations where no remaking was in + fact done. + * job.c (reap_children): Do it here instead, when we know that + actual commands have been run for the file. + * make.h (files_remade): Declare it. + +Thu Nov 5 18:26:10 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * vpath.c (construct_vpath_list): Allow blanks as well as colons to + separate elts in the search path. + + * read.c (read_makefile): Don't fatal on extra tokens in `vpath'. + The search path can contain spaces now. + +Tue Nov 3 20:44:32 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * compatMakefile (check): New target; no-op. + + * file.c (file_hash_enter): Mod OLDHASH by FILE_BUCKETS after + testing for OLDHASH==0 but before using the value. + (rename_file): Don't mod OLDHASH by FILE_BUCKETS before passing it + to file_hash_enter. + + * file.c (rename_file): Notice when OLDFILE->cmds came from + default.c, and don't try to print ->filename in that case. + +Sun Oct 25 01:48:23 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * remake.c (update_file): Don't process F->also_make here. + (notice_finished_file): Don't process FILE->also_make if no attempt + to update FILE was actually made. + Fixed to call f_mtime directly to refresh their modtimes. + +Sat Oct 24 22:08:59 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * read.c (find_percent): Don't increment P again after skipping + an escaped %. + + * expand.c (variable_expand): In call to patsubst_expand, don't + find `%'s ourselves; let that function do it. + + * read.c (read_makefile: record_waiting_files): Don't call + record_files if FILENAMES is nil. + (read_makefile): All alternatives in the parsing, except for rule + lines, fall through to the end of the loop. At the end of the + loop, do record_waiting_files so we notice later spurious cmds. + +Fri Oct 23 15:57:37 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * variable.c (define_automatic_variables): Free old value of SHELL + before replacing it. + +Thu Oct 15 18:57:56 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * compatMakefile (.c.o): Add -I$(srcdir)/glob to flags. + + * dir.c (open_dirstream): Cast return value to __ptr_t. + + * default.c (default_variables: "GET") [_IBMR2]: Use USG defn. + + * make.h (MAXPATHLEN): Moved out of #ifndef POSIX. + (GET_PATH_MAX): Moved from #ifdef POSIX to #ifdef PATH_MAX #else. + Define as (get_path_max ()). + [! PATH_MAX] (NEED_GET_PATH_MAX): Define. + [! PATH_MAX] (get_path_max): Declare fn. + * misc.c [NEED_GET_PATH_MAX] (get_path_max): New function. + +Mon Oct 12 13:34:45 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.62.21. + + * job.c (sys_siglist): Only declare #ifndef SYS_SIGLIST_DECLARED. + * make.h [! HAVE_SYS_SIGLIST && HAVE__SYS_SIGLIST]: #define + SYS_SIGLIST_DECLARED. + + * dir.c (file_impossible): When initializing DIR->contents, set + DIR->contents->dirstream to nil. + + * compatMakefile (GLOB): Define new variable. + (objs): Use it, rather than glob/libglob.a explicitly. + + * read.c (parse_file_seq): When stripping "./", handle cases like + ".///foo" and "./////". + * file.c (lookup_file, enter_file): Likewise. + +Sun Oct 11 17:00:35 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * dir.c (struct dirstream, {open,read}_dirstream): New + data type and functions to read a directory sequentially. + (init_dir): New function to hook it into glob. + * main.c (main): Call init_dir. + + * compatMakefile (objs): Added glob/libglob.a. + * configure.in: Remove code to test for glob. + +Fri Oct 9 12:08:30 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * read.c (record_files): Generalized test for NAME pointing + somewhere into F->name. + + * variable.c (define_variable_in_set): Free old value when replacing. + + * read.c (do_define): Free the linebuffer before returning. + (record_files): When clearing .SUFFIXES deps, free their data. + (multi_glob): Free OLD and its data when replacing it with results + of glob run. + + * commands.c (set_file_variables): Use alloca in place of xmalloc + for temp space for $^, $?, et al. + + * dir.c (struct directory): New member `contents' replaces `files' + and `dirstream'. + (struct directory_contents): New type. + (directories_contents): New hash table. + (dir_struct_file_exists_p): Take a struct directory_contents. + (dir_file_exists_p): Pass it the `contents' member of the dir found. + (dir_struct_file_exists_p): Renamed to dir_contents_file_exists_p; + made static. Return 0 if DIR is nil (meaning it couldn't be stat'd). + (dir_file_exists_p, find_directory): Change all callers. + (file_impossible): Use DIR->contents, initializing it if nil. + (print_dir_data_base): Use DIR->contents, and print out device and + inode numbers with each directory. + + * Changes for performance win from John Gilmore : + * dir.c (DIRECTORY_BUCKETS): Increase to 199. + (DIRFILE_BUCKETS): Decrease to 107. + (find_directory): Allocate and zero a multiple of + sizeof (struct dirfile *), not of sizeof (struct dirfile). + (dir_struct_file_exists_p): New function, nearly all code from + dir_file_exists_p. + (dir_file_exists_p): Just call find_directory+dir_struct_file_exists_p. + * vpath.c (selective_vpath_search): Remove redundant + dir_file_exists_p call. + + * configure.in: Comment out glob check; always use our code. + +Fri Oct 2 19:41:20 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * make.h [! HAVE_SYS_SIGLIST && HAVE__SYS_SIGLIST]: #define + HAVE_SYS_SIGLIST; after doing #define sys_siglist _sys_siglist, we + do have it. + +Wed Sep 30 19:21:01 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * main.c (main): Don't do -w automatically if -s. + +Tue Sep 29 21:07:55 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * main.c (printed_version): Move variable inside print_version. + (print_version): Return immediately if printed_version is set. + (die): Don't test printed_version here. + (decode_switches): Under -v, do print_version before giving usage. + (DESCRIPTION_COLUMN): New macro. + (decode_switches): Use it when printing the usage message. + Leave at least two spaces between options and their descriptions. + +Fri Sep 25 13:12:42 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.62.20. + +Wed Sep 16 16:15:22 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * read.c (read_makefile): Save errno value from trying to open + FILENAME, and restore it before erring; otherwise we get the errno + value from the last elt of the search path. + +Tue Sep 15 15:12:47 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * main.c (long_option_aliases): Add --stop for -S. + + * read.c (word1eq): Do strncmp before dereferencing someplace that + may be out in space. + +Wed Sep 9 15:50:41 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * remake.c (notice_finished_file): If all the command lines were + recursive, don't do the touching. + + * job.c (start_job_command): Don't check for + here. + * commands.c (chop_commands): Do it here instead. + + * default.c (default_terminal_rules): Prepend + to cmds for RCS. + +Wed Sep 2 17:53:08 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * compatMakefile (objs): Include $(ALLOCA). + + * make.h [CRAY]: Move #define signal bsdsignal to before #includes. + +Thu Aug 27 17:45:43 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) + + * read.c (default_include_directories): Add INCLUDEDIR first. + * compatMakefile (includedir): Define. + (defines): Add -D for INCLUDEDIR="$(includedir)". + + * read.c (read_makefile): Grok multiple files in `include'; + globbing too. + + * remake.c (library_search): New function. + (library_file_mtime): Remove function. + (f_mtime): Use library_search instead of library_file_mtime. + * compatMakefile (libdir): Define. + (defines): Add -D for LIBDIR="$(libdir)". + * make.texinfo (Libraries/Search): Document change. + + * file.c (rename_file): Fix file_hash_enter call with missing arg. + +Wed Aug 26 17:10:46 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.62.19. + + * main.c (main): Set command_state to cs_finished for temp files + made for stdin makefiles. + + * main.c (decode_switches): Don't tell getopt to return non-option + args in order. + Ignore an argument of `-'. + +Thu Aug 20 13:36:04 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * job.c (start_job_command): If (touch_flag && !RECURSIVE), ignore + the command line and go to the next. + (notice_finished_file): Under -t, touch FILE. + * remake.c (remake_file): Don't touch it here. + +Wed Aug 19 16:06:09 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * function.c (pattern_matches): Use temporary for strlen (WORD) + instead of two function calls. + + * compatMakefile (LOAD_AVG): Remove variable and comments. + +Tue Aug 18 14:58:58 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * make.texinfo (Running): Node renamed to `make Invocation'. + +Fri Aug 14 12:27:10 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * arscan.c (ar_name_equal): Don't compare [MAX-3..MAX] if + NAMELEN != MEMLEN. + +Thu Aug 13 17:50:09 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.62.18. + + * main.c: Don't #include ; make.h already does. + +Mon Aug 10 17:03:01 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * implicit.c (pattern_search): Fixed copying of suffix when building + also_make elts. + + * function.c (expand_function: `shell'): Make sure BUFFER is + null-terminated before replacing newlines. + + * compatMakefile (mandir): Use man$(manext), not always manl. + +Sun Aug 2 01:42:50 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * rule.c (new_pattern_rule): Not static. + * rule.h: Declare it. + + * file.c (file_hash_enter): New function, most code from rename_file. + (rename_file): Call it. + * file.h (file_hash_enter): Declare it. + + * dep.h: Doc fix. + +Thu Jul 30 15:40:48 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * main.c (decode_switches): Handle usage_and_exit when building + long options vector. + + * default.c (default_terminal_rules): Make RCS rules use $(CHECKOUT,v). + (default_variables): Define CHECKOUT,v (hairy). + + * make.h [!HAVE_SYS_SIGLIST && HAVE__SYS_SIGLIST]: #define + sys_siglist to _sys_siglist. + +Sun Jul 26 16:56:32 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * NEWS: Add header and tail copyright info like Emacs NEWS. + + * make.h [ANSI_STRING]: Don't #define index, rindex, bcmp, bzero, + bcopy if already #define'd. + [STDC_HEADERS] (qsort, abort, exit): Declare here. + [! __GNU_LIBRARY__ && !POSIX]: Not here. + + * make.h [_AIX]: #pragma alloca first thing. + + * job.c (start_waiting_job): Set the command_state to cs_running + when we queue a job on waiting_jobs. + +Fri Jul 24 02:16:28 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * variable.c (define_automatic_variables): Use "" instead of nil + for empty value. + +Thu Jul 23 22:31:18 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.62.17. + + * main.c (struct command_switch.type): Add alternative usage_and_exit. + (command_switches): Add -h/--help. + +Thu Jul 16 14:27:50 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * GNUmakefile (make-$(version).tar.Z): Include NEWS, not CHANGES. + * README.template: Mention NEWS. + * CHANGES: Renamed to NEWS. + + * main.c [! STDC_HEADERS] [sun]: Don't declare exit. + +Tue Jul 14 18:48:41 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * main.c (main): Set -o files' command_states to cs_finished. + + * rule.c (count_implicit_rule_limits): Decrement num_pattern_rules + when tossing a rule. + + * main.c (main): Use alloca only in simple local var assignment, + for braindead SGI compiler. + + * rule.c (print_rule_data_base): Barf if num_pattern_rules is + inconsistent with the number computed when listing them. + +Mon Jul 13 17:51:53 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * commands.c (set_file_variables): For $? and $^ elts that are archive + member refs, use member name only. + +Fri Jul 10 00:05:04 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * variable.h (struct variable.export): Add new alternative v_ifset. + * variable.c (target_environment): Check for it. + (define_automatic_variables): Set it for MAKEFILES. + +Thu Jul 9 21:24:28 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * compatMakefile (objs): Remove getloadavg.o; $(extras) gets it. + (remote.o): Use $(srcdir)/remote.c, not $remote.c<. + (distclean, mostlyclean): New targets. + +Tue Jul 7 19:12:49 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.62.16. + + * compatMakefile (config.status): Remove rule. + + * job.c (start_waiting_job): Free C after using C->file, not before. + +Sat Jul 4 20:51:49 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * commands.c, job.c, main.c, make.h, remote-cstms.c: Use #ifdef + HAVE_* instead of #ifndef *_MISSING. + * configure.in: Use AC_HAVE_FUNCS instead of AC_MISSING_FUNCS (gone). + +Thu Jul 2 18:47:52 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * main.c (main): makelevel>0 or -C implies -w. + +Tue Jun 30 20:50:17 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * file.c, job.c, function.c: Don't #include . + make.h: Do it here instead. + * arscan.c (ar_member_touch): Don't declare errno. + +Thu Jun 25 17:06:55 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * GNUmakefile (make-$(version).tar.Z): Depend on INSTALL, configure.in. + + * remake.c (update_file): If commands or deps are running after + update_file_1 returns, break out of the :: rule (->prev) loop and + just return. + + * job.c (job_next_command): New function; code from start_job. + (start_job_command): Renamed from start_job. Call job_next_command + and recurse for empty command lines and -n. + (start_waiting_job): Call start_job_command, not start_job. + (new_job): Call job_next_command to prime the child structure, and + then call start_waiting_job. + (reap_children): Use job_next_command and start_job_command. + (start_waiting_job): Call start_remote_job_p here, and store its + result in C->remote. If zero, check the load average and + maybe put C on waiting_jobs. + (start_job_command): Test CHILD->remote rather than calling + start_remote_job_p. Don't do load avg checking at all here. + + * main.c (main): Don't handle SIGILL, SIGIOT, SIGEMT, SIGBUS, + SIGSEGV, SIGFPE or SIGTRAP. + + * compatMakefile (glob/libglob.a): Don't pass srcdir to sub-make. + configure will set it in glob/Makefile. + +Wed Jun 24 19:40:34 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * dir.c [DIRENT] (direct): Don't define to dirent. + [! DIRENT] (direct): Define to dirent. + (dir_file_exists_p): Use struct dirent instead of struct direct. + + * make.h (getcwd): No space between macro and ( for args! + + * job.c (start_job): Don't put the job on waiting_jobs if + job_slots_used==0. + + * make.texinfo (Missing): Shortened title. + +Tue Jun 23 18:42:21 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * file.c (remove_intermediates): Print "rm" commands under -n. + +Mon Jun 22 16:20:02 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.62.15. + +Fri Jun 19 16:20:26 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * arscan.c [M_UNIX]: #undef M_XENIX. + +Wed Jun 17 17:59:28 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * default.c (default_terminal_rules): Put @ prefix on RCS cmds. + +Tue Jun 16 19:24:17 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * compatMakefile (getloadavg.o): Removed special rule. + (CFLAGS): Don't include $(defines). + (.c.o): Define suffix rule. + (glob/libglob.a): Pass CPPFLAGS=$(defines) to submake. + (GETOPT_SRC, srcs, tagsrcs): Prefix files with $(srcdir)/. + + * arscan.c (ar_name_equal): Moved local vars inside #if'd block. + + * make.h (max): Removed. + * expand.c (variable_buffer_output): Don't use it. + + * compatMakefile (INSTALL): Define. + (Makefile): New rule to make from Makefile.in. + (srcdir): Define. + (VPATH): Define. + (getloadavg.o, remote.o): Use autoconf $foo< hack. + + * commands.c (fatal_error_signal): Removed return. + +Mon Jun 15 17:42:51 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.62.14. + + * make.texinfo (Summary): New node. + (Special Targets): Mention .EXPORT_ALL_VARIABLES here. + + * variable.c (max): Moved to make.h. + + * compatMakefile (objs, srcs): Added ar & arscan. + + * job.c (start_waiting_job): New function, 2nd half of new_job. + (new_job): Call it. + (start_waiting_jobs): New function. + * remake.c (update_goal_chain): Call start_waiting_jobs at the top + of the main loop. + * compatMakefile (objs, srcs): Removed load, added getloadavg. + +Fri Jun 12 19:33:16 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * job.c (load_too_high): New function. Uses getloadavg. + (waiting_jobs): New variable. + (start_job): Don't call wait_to_start_job. Instead, if + load_too_high returns nonzero, add the child to the + `waiting_jobs' chain and return without starting the job. + +Thu Jun 11 00:05:28 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * expand.c (variable_buffer_output): Made global again. + * variable.h: And declare it. + + * arscan.c (PORTAR): Define for all systems if PORT5AR is not defined. + (AR_NAMELEN, AR_TRAILING_SLASH): Removed. + (ar_scan): Don't use it. Don't #ifdef AR_TRAILING_SLASH; just look + for a slash in the archive at run time. + (ar_name_equal): Rewrote .o hacking to not use AR_NAMELEN, and to + cope with trailing-slash and non-trailing-slash archives. + + * main.c (main) [! SETVBUF_REVERSED]: Test this instead of USGr3 et al. + [SETVBUF_REVERSED]: Always allocate a buffer ourselves. + + * load.c (load_average) [sgi]: Use sysmp call. + + * compatMakefile (INSTALL_DATA, INSTALL_PROGRAM): Define. + ($(bindir)/$(instname), $(mandir)/make.$(manext)): Use them. + + * make.h [HAVE_VFORK_H]: #include . + (vfork, VFORK_NAME): Don't define. + * job.c (start_job): Use "vfork" in place of VFORK_NAME. + + * make.h [HAVE_LIMITS_H, HAVE_SYS_PARAM_H]: If #define'd, #include + the each file. Rearranged PATH_MAX hacking. + * job.c: Rearranged NGROUPS_MAX hacking. + + * remake.c (fstat, time): Don't declare. + + * compatMakefile (defines): Value is @DEFS@. + (LOADLIBES): Value is @LIBS@. + (extras): Value is @LIBOBJS@. + (ARCHIVES, ARCHIVES_SRC, ALLOCASRC): Removed. + * arscan.c, ar.c: Surround body with #ifndef NO_ARCHIVES. + + * misc.c [! HAVE_UNISTD_H]: Test instead of !POSIX to decl get*id. + + * make.h [GETCWD_MISSING]: Test instead of !USG && !POSIX et al. + (getcwd): Just declare if present. If not, declare as a macro + using getwd, and declare getwd. + [PATH_MAX] (GET_PATH_MAX): #define to PATH_MAX. + * main.c (main, log_working_directory): Use getcwd instead of getwd. + + * main.c (main) [SETLINEBUF_MISSING]: Test this instead of USG. + + * make.h (SIGHANDLER, SIGNAL): Removed. + (RETSIGTYPE): Define if not #define'd. + * main.c (main): Use signal in place of SIGNAL. + + * main.c [SYS_SIGLIST_MISSING]: Test instead of USG. + + * job.c (search_path) [GETGROUPS_MISSING]: Test instead of USG. + [HAVE_UNISTD_H]: Test instead of POSIX to not decl getgroups. + + * main.c [! HAVE_UNISTD_H]: Test instead of !POSIX to decl chdir. + [! STDC_HEADERS]: Test instead of !POSIX to decl exit & atof. + + * job.c (child_handler), commands.c (fatal_error_signal): Return + RETSIGTYPE instead of int. + * main.c (main): Declare fatal_error_signal and child_handler here + to return RETSIGTYPE; removed top-level decl of former. + + * commands.c (fatal_error_signal), job.c (unblock_sigs, start_job), + main.c [SIGSETMASK_MISSING]: Test this instead of USG. + +Wed Jun 10 22:06:13 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * job.c [HAVE_WAITPID]: Test this instead of USG. + [! HAVE_UNISTD_H]: Test this instead of !POSIX to declare misc fns. + (GID_T): Don't #define. + (search_path): Use gid_t instead of GID_T. + [GETDTABLESIZE_MISSING, SYS_SIGLIST_MISSING, DUP2_MISSING]: Test + these individually instead of USG for all. + * make.h (ctime): Don't declare. #include time.h instead. + [HAVE_UNISTD_H]: #include and #define POSIX #ifdef + _POSIX_VERSION. + * dir.c [__GNU_LIBRARY__] (D_NAMLEN): Define to use d_namlen member. + * make.h [NEED_MEMORY_H]: Only include memory.h #ifdef this. + + * arscan.c: Removed #ifdef mess about string.h et al. + Just #include make.h instead. + * make.h (fstat, atol): Declare. + + * commands.c (fatal_error_signal): Don't use sigmask to check for + propagated signals; use ||s instead. + (PROPAGATED_SIGNAL_MASK): Removed. + (fatal_error_signal) [POSIX]: Use sigprocmask in place of sigsetmask. + + * variable.c (variable_buffer, variable_buffer_length, + initialize_variable_output, variable_output): Moved to expand.c; + made all static. + (struct output_state, save_variable_output, + restore_variable_output): Removed. + * expand.c (initialize_variable_output): Put a NUL at the beginning + of the new buffer after allocating it. + (allocated_variable_expand_for_file): Don't use + {save,restore}_variable_output. Do it by hand instead, keeping + state on the stack instead of malloc'ing it. + (allocated_variable_expand): Removed. + * variable.h (allocated_variable_expand): Define here as macro. + (variable_buffer_output, initialize_variable_output, + save_variable_output, restore_variable_output): Removed decls. + + * read.c (conditional_line): For an if cmd, if any elt of the + conditionals stack is ignoring, just push a new level that ignores + and return 1; don't evaluate the condition. + +Thu Jun 4 21:01:20 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * main.c (main): Put #ifdef's around frobbing SIGSYS and SIGBUS. + + * job.c (getdtablesize): Don't declare or #define if already #define'd. + +Wed Jun 3 23:42:36 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * file.c (snap_deps): If `.EXPORT_ALL_VARIABLES' is a target, set + export_all_variables. + * make.texinfo (Variables/Recursion): Document .EXPORT_ALL_VARIABLES. + +Tue Jun 2 21:08:35 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.62.13. + + * commands.c (set_file_variables): Calculate length for ^D and ?D + individually, making sure to give them at least enough space for "./". + + * make.h [CRAY]: #define signal to bsdsignal. + + * default.c (default_variables) [CRAY]: Define PC, SEGLDR, + CF77PPFLAGS, CF77PP, CFT, CF, and FC. + + * arscan.c (AR_HDR_SIZE): Define to sizeof (struct ar_hdr), if it + wasn't defined by . + +Thu May 28 00:56:53 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.62.12. + +Tue May 26 01:26:30 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * rule.c (new_pattern_rule): Initialize LASTRULE to nil, not + pattern_rules. + +Mon May 25 19:02:15 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * main.c (decode_switches): Initialize all the long_option elt members. + +Thu May 21 16:34:24 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) + + * make.texinfo (Text Functions): Correct filter-out description. + +Tue May 19 20:50:01 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * compatMakefile (realclean): Don't remove backup files. + + * main.c (decode_switches): Allocate ARGC+1 elts in `other_args'. + +Sun May 17 16:38:48 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * Version 3.62.11. + +Thu May 14 16:42:33 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * job.c (reap_children): Don't die if wait returns EINTR. + +Wed May 13 18:28:25 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * job.c (reap_children): Always run the next command for a + successful target. If we are going to die, we don't want to leave + the target partially made. + +Tue May 12 00:39:19 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * job.c (construct_command_argv_internal): After loop, if we only + have one word, check it for being a shell command. + + * main.c (decode_switches): Allocate ARGC slots in other_args to + begin with, so we never need to worry about growing it. + If we get a non-option arg and POSIXLY_CORRECT is in the + environment, break out of the loop. After the loop, add all remaining + args to other_args list. + + * main.c (decode_switches): For positive_int and floating switches + when optarg is nil, use next arg if it looks right (start with a + digit, or maybe decimal point for floating). + + * variable.c (define_automatic_variables): Always set SHELL to + default if it comes from the environment. Set its export bit. + * make.texinfo (Environment): Document change. + +Mon May 11 00:32:46 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * Version 3.62.10. + + * compatMakefile (tags, TAGS): Use vars for cmds. + (ETAGS, CTAGS): Define. + + * main.c (decode_switches): If a switches elt has a nil long_name, + make the long option name elt be "". + Fixed loop to not ignore all the options. + + * make.texinfo (Option Summary): Added long options. + + * main.c (switches): Changed -m's description to "-b". + (decode_switches): When printing the usage message, don't print + switches whose descriptions start with -. + When constructing the list of names for switch -C, search the + switches vector for switches whose descriptions are "-C". + + * main.c (switches): Call -S --no-keep-going, not --dont-keep-going. + Call -I --include-dir, not --include-path. + (long_option_aliases): Added --new == -W, --assume-new == -W, + --assume-old == -o, --max-load == -l, --dry-run == -n, --recon == -n, + --makefile == -f. + + * main.c (switches): Removed bogus "silent" elt. + (long_option_aliases): Define new var. + (decode_switches): Add long_option_aliases onto the end of the long + options vector created for getopt_long. + Look through long_option_aliases for extra names to list + in usage message. + +Sat May 9 00:21:05 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * main.c (log_working_directory): Fixed to properly not print the + leaving message when we haven't printed the entering message. + +Fri May 8 21:55:35 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * main.c (struct command_switch): Added elts `long_name', + `description', and `argdesc'. + (switches): Added initializers for new members. + (decode_switches): Rewritten to use getopt_long. + * compatMakefile (GETOPT, GETOPT_SRC): Define. + (objs, srcs): Include them. + + * job.c (child_died): Renamed to dead_children; made static. + (child_handler): Increment dead_children instead of setting child_died. + (reap_children): Decrement dead_children instead of clearing + child_died. The point of all this is to avoid printing "waiting + for unfinished jobs" when we don't actually need to block. + This happened when multiple SIGCHLDs before reap_children was called. + + * job.c (reap_children): If ERR is set, so we don't call start_job + on the child being reaped, instead set its command_state to + cs_finished. + (reap_children, child_handler, new_job): I added several + debugging printf's while fixing this. I left them in if (debug_flag) + because they may be useful for debugging this stuff again. + +Wed May 6 22:02:37 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * read.c (read_makefile): v_export is not 1. + +Mon May 4 17:27:37 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.62.9. + + * variable.c (export_all_variables): New variable. + (target_environment): Export variables whose `export' member is + v_default if export_all_variables is set and their names are benign. + * variable.h: Declare export_all_variables. + * read.c (read_makefile): If export or unexport is given with no + args, set or clear export_all_variables, respectively. + + * variable.c (target_environment): Exclude MAKELEVEL in the loop, + so it isn't duplicated when we add it at the end. + +Sun May 3 17:44:48 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.62.8. + + * variable.h (struct variable): Added new member `export'. + * variable.c (define_variable_in_set): Initialize it to v_default. + (target_environment): Don't check for .NOEXPORT. + Export variables whose `export' member is v_default and that would + have been exported under .NOEXPORT, and variables whose `export' + member is v_export. + (try_variable_definition): Return the variable defined. + * variable.h (try_variable_definition): Changed decl. + * read.c (read_makefile): Recognize `export' and `unexport' directives. + +Fri May 1 11:39:38 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * main.c (main) [POSIX]: Reversed args to sigaddset. + +Thu Apr 30 17:33:32 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * job.c [POSIX || !USG] (unblock_sigs): New fn. + (start_job): Block signals before forking. + (new_job): Unblock signals after putting the new child on the chain. + * main.c (main) [POSIX]: Use sigset_t fatal_signal_set instead of + int fatal_signal_mask. + + * load.c [sgi] (LDAV_CVT): Define. + +Wed Apr 29 17:15:59 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * Version 3.62.7. + + * load.c (load_average) [sgi]: Clear the high bit of the address + from the symbol table before looking it up in kmem. + + * misc.c (fatal, makefile_fatal): Put *** in fatal error messages. + (remake_file): No longer needed in message here. + + * main.c (die): Call reap_children with BLOCK==1. + +Tue Apr 28 20:44:35 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * rule.c (freerule): Don't set LASTRULE->next if LASTRULE is nil. + +Sun Apr 26 15:09:51 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * rule.c (count_implicit_rule_limits): Initialize LASTRULE to nil, + not to head of chain. Extract next ptr before we might do + freerule, and use that for next iteration. + (freerule): Still do next ptr frobbing if LASTRULE is nil. + +Tue Apr 21 03:16:29 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * job.c (child_error): Removed extra %s from error msg format. + + * Version 3.62.6. + + * job.c (reap_children): Don't start later commands in a sequence + if ERR is nonzero. + + * job.c (new_job): Always call reap_children with BLOCK==0 first thing. + + * job.c (reap_children): New function; work that used to be done in + child_handler. + (child_died): New global var. + (child_handler): Now just sets child_died. + (wait_for_children): Removed. + (unknown_children_possible, block_signals, unblock_signals, + push_signals_blocked_p, pop_signals_blocked_p): Removed. + (child_execute_job): Removed call to unblock_signals. + (new_job): Removed calls to push_signals_blocked_p and + pop_signals_blocked_p. + * job.h: Declare reap_children, not wait_for_children. + * commands.c (fatal_error_signal), job.c (new_job), + load.c [LDAV_BASED] (wait_to_start_job), main.c (die), + remake.c (update_goal_chain), function.c (expand_function: `shell'): + Changed wait_for_children calls to reap_children. + Some needed to be loops to wait for all children to die. + * commands.c (fatal_error_signal), main.c (main, + log_working_directory), function.c (expand_function): Removed calls + to push_signals_blocked_p and pop_signals_blocked_p. + * job.h: Removed decls. + + * job.h: Added copyright notice. + +Wed Apr 15 02:02:40 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * job.c (child_error): No *** for ignored error. + +Tue Apr 14 18:31:21 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * implicit.c (DEBUGP2): Use do ... while (0) instead of if ... else to + avoid compiler warnings. + + * read.c (parse_file_seq): Don't remove ./ when it is followed by a + blank. + +Mon Apr 13 21:56:15 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * make.h (DEBUGPR): Use do ... while (0) instead of if ... else to + avoid compiler warnings. + + * remake.c (notice_finished_file): Run file_mtime on the also_make + files, so vpath_search can happen. + + * GNUmakefile (tests): Use perl test suite from csa@sw.stratus.com. + (alpha-files): Include test suite tar file. + +Fri Apr 3 00:50:13 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * Version 3.62.5. + +Wed Apr 1 05:31:18 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * remake.c (update_file, update_file_1): Do check_renamed on elts + of dep chains when traversing them. Something unrelated might have + renamed one of the files the dep chain points to. + + * file.c (rename_file): If FILE has been renamed, follow its + `renamed' ptr, so we get to the final real FILE. Using the renamed + ones loses because they are not in the hash table, so the removal + code loops infinitely. + + * read.c (read_all_makefiles): Clobber null terminator into + MAKEFILES expansion, so string passed to read_makefile is properly + terminated. + +Mon Mar 30 20:18:02 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * commands.c (set_file_variables): $* for archive member with + explicit cmds is stem of member, not of whole `lib(member)'. + +Thu Mar 26 15:24:38 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * Version 3.62.4. + +Tue Mar 24 05:20:51 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * rule.c (new_pattern_rule): Rules are identical only if all their + targets match (regardless of order). + +Wed Mar 11 13:49:54 1992 Roland McGrath (roland@geech.gnu.ai.mit.edu) + + * remake.c (remake_file): Changed error "no way to make" to "no + rule to make". Fiat Hugh. + + * make.texinfo (Last Resort): Describe %:: rules and new .DEFAULT + behavior. + + * remake.c (update_file_1): Only use .DEFAULT cmds if FILE is not a + target. + +Tue Mar 10 18:13:13 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) + + * remote-stub.c, remote-cstms.c (start_remote_job): Take new arg, + environment to pass to child. + * job.c (start_job): Pass it. + +Mon Mar 9 19:00:11 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * file.c (enter_file): Also strip ./s here, to get command-line + target names. + + * remote-cstms.c: Add comment telling people to leave me alone. + + * compatMakefile (manpage install): Remove target before copying. + +Tue Mar 3 18:43:21 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * make.texinfo (Missing): Renamed to "Incompatibilities and ...". + Added paragraph describing $? incompatibility with Unix and POSIX.2. + +Sun Mar 1 15:50:54 1992 Roland McGrath (roland@nutrimat.gnu.ai.mit.edu) + + * function.c (expand_function: `shell'): Don't declare fork or pipe. + Use vfork instead of fork. + +Tue Feb 25 22:05:32 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) + + * make.texinfo (Chained Rules): Clarify .PRECIOUS to save + intermediate files. + + * load.c [sun] (LDAV_CVT): Define to divide by FSCALE. + +Sun Feb 16 02:05:16 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) + + * Version 3.62.3. + +Sat Feb 15 17:12:20 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) + + * compatMakefile (makeinfo): Use emacs batch-texinfo-format fn. + +Fri Feb 14 00:11:55 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) + + * read.c (read_makefile): Correctly handle define & endef in ifdefs. + + * read.c (record_files): Pass arg for %s in error msg. + + * main.c (main) [__IBMR2, POSIX]: Use correct (a la USGr3) setvbuf + call. + +Wed Feb 12 12:07:39 1992 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) + + * make.texinfo (Libraries/Search): Say it does /usr/local/lib too. + +Sun Feb 9 23:06:24 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * read.c (read_makefile): Check for extraneous `endef' when ignoring. + +Thu Feb 6 16:15:48 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * Version 3.62.2. + +Tue Feb 4 20:04:46 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * job.c (construct_command_argv_internal): Correctly ignore + whitespace after backslash-NL. + +Fri Jan 31 18:30:05 1992 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * compatMakefile: Ignore errors from chgrp and chmod when installing. + +Wed Jan 29 18:13:30 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * main.c (main): When setting MAKELEVEL in the env to re-exec, + allocate space so as not to clobber past the end of the old string. + + * make.h [HAVE_ALLOCA_H]: Include + * compatMakefile (defines): Document HAVE_ALLOCA_H. + +Mon Jan 20 13:40:05 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * make.h [VFORK_MISSING]: Use fork instead. + * compatMakefile (defines): Document same. + + * job.c (construct_command_argv_internal): Don't create an empty + arg if backslash-NL is at beginning of word. + +Sun Jan 19 16:26:53 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * main.c [DGUX]: Call setvbuf as for USGr3. + + * job.c (construct_command_argv_internal): Notice correctly that + backslash-NL is the end of the arg (because it is replaced with a + space). + +Thu Jan 16 18:42:38 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * job.c (construct_command_argv_internal): If SHELL is nil, set it + to default_shell before proceeding. + + * make.h [sgi]: No alloca.h, after all. + +Wed Jan 15 12:30:04 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * read.c (multi_glob): Cons up the chain of the results of glob + from back to front, so it comes out in forward order. + + * job.c (construct_command_argv_internal): Don't eat char following + backslash-NL. + +Mon Jan 13 19:16:56 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * Version 3.62.1. + + * default.c (default_variables) [ultrix]: GET=get, like USG. + + * job.c (construct_command_argv_internal): Remove tabs following + backslash-NL combos in the input line, so they don't show up when + that line is printed. + + * read.c (read_makefile): Don't collapse_continuations the line on + input; do it on the copy we do remove_comments on. + For rule lines, collapse_continuations the line after chopping + ";cmds" off the end, so we don't eat conts in the cmds. + Give error for ";cmds" with no rule. + * job.c (construct_command_argv_internal): Eat backslash-NL combos + when constructing the line to recurse on for slow, too. + +Sat Jan 11 02:20:27 1992 Roland McGrath (roland@albert.gnu.ai.mit.edu) + + * file.c (enter_file): Don't strip leading `./'s. + * read.c (parse_file_seq): Take new arg STRIP; if nonzero, do it here. + * default.c (set_default_suffixes), function.c (string_glob), + read.c (read_makefile), rule.c (install_pattern_rule): Change callers. + + * default.c (default_variables) [_IBMR2]: FC=xlf + + * job.c (construct_command_argv_internal): Turn backslash-NL and + following whitespace into a single space, rather than just eating + the backslash. + + * make.texinfo (Copying): @include gpl.texinfo, rather than + duplicating its contents. + +Fri Nov 8 20:06:03 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * job.c (construct_command_argv_internal): Make sure not to bother + processing an empty line. + + * Version 3.62.0. + + * job.c (construct_command_argv_internal): Always recurse for slow; + simple case didn't handle finding newlines. + +Tue Nov 5 18:51:10 1991 Roland McGrath (roland@wookumz.gnu.ai.mit.edu) + + * job.c (construct_command_argv_internal): Set RESTP properly when + slow; don't \ify past a newline. + +Fri Nov 1 19:34:28 1991 Roland McGrath (roland@churchy.gnu.ai.mit.edu) + + * make.h [sgi]: #include . + + + +See ChangeLog.1, available in the Git repository at: + + http://git.savannah.gnu.org/cgit/make.git/tree/ + +for earlier changes. + + +Copyright (C) 1991-2007 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . diff --git a/src/kmk/ChangeLog.3 b/src/kmk/ChangeLog.3 new file mode 100644 index 0000000..5fcf273 --- /dev/null +++ b/src/kmk/ChangeLog.3 @@ -0,0 +1,5633 @@ +2013-10-09 Paul Smith + + Version 4.0 released. + + * configure.ac: Updated for the release. + * NEWS: Updated for the release. + + * maintMakefile (tag-release): New target to add a Git tag. + * read.c (eval): Typo fix. + * ChangeLog.1: Typo fixes. + * w32/subproc/sub_proc.c (process_cleanup): Typo fix. + +2013-10-07 Eli Zaretskii + + * w32/compat/posixfcn.c (tmpfile): Move declaration of h before + the first executable statement. Reported by Gisle Vanem + . + +2013-10-05 Paul Smith + + * makeint.h (MAP_USERFUNC): A new map type for function names. + * main.c (initialize_stopchar_map): Set up the function name map. + + * gnumake.h (gmk_func_ptr): Define a type for function pointers. + (gmk_add_function): Convert the last argument to FLAGS. + (GMK_FUNC_*): Define flags for the function. Change the default + behavior to "expand" since that's the most common one. + + * function.c (function_table_entry): Use new function pointer type. + (lookup_function): Accept any valid function name character based + on the MAP_USERFUNC values. + (define_new_function): Use the new calling signature. Verify that + registered functions have valid names. + + * guile.c (guile_gmake_setup): Use new calling signatures. + * loadapi.c (gmk_add_function): Ditto. + * variable.h (define_new_function): Ditto. + + * doc/make.texi (Loaded Object API): Make the registered function + API documentation more clear. + +2013-10-03 Eli Zaretskii + + * function.c (abspath): Reset root_len to one for Cygwin only when + HAVE_DOS_PATHS is defined. Suggested by Christopher Faylor. + +2013-10-02 Eli Zaretskii + + * w32/compat/posixfcn.c (tmpfile): New function, a replacement for + the Windows libc version. + + Fix $abspath on Cygwin when HAVE_DOS_PATHS is in effect. + * function.c (IS_ABSOLUTE) [__CYGWIN__]: Special definition for + Cygwin. + (abspath) [__CYGWIN__]: Reset root_len to 1 if the absolute file + name has the Posix /foo/bar form. + [HAVE_DOS_PATHS]: Use root_len instead of hard-coded 2. + +2013-10-01 Paul Smith + + * configure.ac: Update version to 3.99.93. + * NEWS: Ditto. + +2013-09-30 Paul Smith + + * guile.c: Portability fixes for Guile 1.8. + +2013-09-29 Paul Smith + + * output.c (output_dump): Always write Enter/Leave messages to stdio. + (log_working_directory): This now always writes to stdio, so we + don't need the struct output parameter anymore. + (output_start): Show the working directory when output_sync is not + set or is recursive. + * main.c (main): Ensure the special "already shown Enter message" + token is removed from MAKE_RESTARTS before the user can see it. + * function.c (func_shell_base): If the output_context stderr + exists but is invalid, write to the real stderr. + Fixes suggested by Frank Heckenbach . + + * output.c: Guard unistd.h inclusion, add io.h. + * gnumake.h: Move GMK_EXPORT before the declarations. + * make_msvc_net2003.vcproj: Add missing files. + Changes for MSVC suggested by Gerte Hoogewerf + + * function.c (func_shell_base) [EMX]: Fix EMX support for output-sync. + * job.c (child_execute_job) [EMX]: Ditto. + * job.h (child_execute_job) [EMX]: Ditto. + * w32/compat/posixfcn.c: Invert the test for NO_OUTPUT_SYNC. + + * guile.c (GSUBR_TYPE): Pre-2.0 Guile doesn't provide a typedef + for gsubr pointers. Create one. + (guile_define_module): Use it. + (internal_guile_eval): Force UTF-8 encoding for Guile strings. + + * main.c (main): Clear GNUMAKEFLAGS after parsing, to avoid + proliferation of options. + * NEWS: Document it. + * doc/make.texi (Options/Recursion): Ditto. + +2013-09-23 Eli Zaretskii + + * w32/compat/posixfcn.c: Fix the forgotten OUTPUT_SYNC conditional. + + * job.h: Ditto, but in a comment. + +2013-09-22 Paul Smith + + * configure.ac: Update version to 3.99.92. + * NEWS: Ditto. + + * implicit.c (pattern_search): After second expansion be sure to + handle order-only markers inside the expansion properly. + Fixes Savannah bug #31155. + + * guile.c (guile_define_module): Technically a void* cannot + contain a pointer-to-function and some compilers warn about this. + Cast the function pointers. + * load.c (load_object): Ditto. + + * read.c (eval): If load_file() returns -1, don't add this to the + "to be rebuilt" list. + * doc/make.texi (load Directive): Document it. + + * guile.c (guile_gmake_setup): Don't initialize Guile so early. + (func_guile): Lazily initialize Guile the first time the $(guile ..) + function is invoked. Guile can steal file descriptors which + confuses our jobserver FD checking, so we don't want to initialize + it before we have to. + + VMS port updates by Hartmut Becker + + * makefile.com: Add output to the filelist. + * output.c (va_copy): Add an implementation of this macro for VMS. + * commands.c: Ensure filedef.h is #included before dep.h. + * dir.c: Ditto. + * file.c: Ditto. + * guile.c: Ditto. + * main.c: Ditto. + * misc.c: Ditto. + * read.c: Ditto. + * rule.c: Ditto. + * variable.c: Ditto. + * readme.vms: Renamed to README.VMS and updates for this release. + * Makefile.am: Ditto. + * NEWS: Ditto. + * README.template: Ditto. + * Makefile.DOS.template: Ditto. + +2013-09-21 Paul Smith + + * maintMakefile (check-alt-config): Create a target to test + alternative configurations. Each one will build make with a + different configuration then run the test suite. + + Invert the output-sync #define to NO_OUTPUT_SYNC + + * configure.ac: Don't set OUTPUT_SYNC. + * makeint.h: Ditto. + * main.c: Use NO_OUTPUT_SYNC instead of OUTPUT_SYNC. + * output.c: Ditto. + * output.h: Ditto. + * job.h: Ditto. + * job.c: Ditto. + * config.ami.template: Set NO_OUTPUT_SYNC. + * config.h-vms.template: Ditto. + * config.h.W32.template: Ditto. + * configh.dos.template: Ditto. + + Output generated while reading makefiles should be synced. + + * main.c (make_sync): Define a context for syncing while reading + makefiles and other top-level operations. + (main): If we request syncing, enable it while we are parsing + options, reading makefiles, etc. to capture that output. Just + before we start to run rules, dump the output if any. + (die): Dump any output we've been syncing before we die + * output.h (OUTPUT_SET): Disable output_context if not syncout. + + Stderr generated from shell functions in recipes should be synced. + + * job.h (FD_STDIN, FD_STDOUT, FD_STDERR): Create new macros to + avoid magic numbers. + (child_execute_job): Take a FD for stderr. + * job.c (child_execute_job): Handle STDERR FD's in addition to + stdin and stdout. + (start_job_command): Call child_execute_job() with the new STDERR + parameter. Instead of performing the dup() here, send it to + child_execute_job() where it's already being done. + * function.c (func_shell_base): Pass the OUTPUT_CONTEXT stderr to + child_execute_job() if it's set, otherwise FD_STDERR. + * main.c (main): Pass FD_STDERR to child_execute_job(). + +2013-09-19 Paul Smith + + * main.c (main): Set MAKE_RESTARTS to negative before re-exec if + we've already generated an "Entering" message. If we are started + and notice that MAKE_RESTARTS is negative, assume we already wrote + "Entering" and don't write it again. + +2013-09-18 Paul Smith + + * main.c (main): Set starting_directory before we write any + errors. Fixes Savannah bug #40043. + +2013-09-16 Eli Zaretskii + + * output.c [WINDOWS32]: Include windows.h and sub_proc.h, to avoid + compiler warnings for CLOSE_ON_EXEC. + +2013-09-16 Paul Smith + + * configure.ac: Update version to 3.99.91. + * NEWS: Ditto. + +2013-09-15 Paul Smith + + * doc/make.texi (Error Messages): Add a bit more info to the + section on static pattern errors, since they're common. + Fixes Savannah bug #31326. + + * read.c (eval_makefile): If the file open fails with an + unrecoverable error, stop now rather than trying to make it. + Fixes Savannah bug #27374. + + * main.c (main): Perform the validation of the jobserver FDs + early, before we read makefiles, to ensure that something hasn't + opened and used those FDs for some other reason. + Fixes Savannah bug #39934. + + * main.c (main): Don't set MAKEFLAGS in the environment when we + restart. We have the original command line flags so keep the + original MAKEFLAGS settings as well. + Fixes Savannah bug #39203. + +2013-09-14 Paul Smith + + * main.c (decode_debug_flags): Add support for the "n" flag to + disable all debugging. + * make.1: Document the "n" (none) flag. + * doc/make.texi (Options Summary): Ditto. + * NEWS: Ditto. + Fixes Savannah bug #35248. + + * misc.c (close_stdout): Move to output.c. + * main.c (main): Move atexit call to output_init(). + * makeint.h: Remove close_stdout() declaration. + * output.c (output_init): Add close_stdout at exit only if it's open. + Fixes Savannah bug #33134. Suggested by David Boyce . + +2013-09-14 Paul Smith + + * misc.c (set_append_mode, open_tmpfd, open_tmpfile): Move to output.c. + * misc.h: Ditto. + * output.h: Ditto. + * main.c (main): Move stdio init into output.c:output_init(). + Change open_tmpfile() to output_tmpfile(). + * output.c: Rename open_*() to output_*(). set_append_mode() and + open_tmpfd() are static. + (_outputs, log_working_directory): Accept a struct output and + print to that rather than the global context. + (output_dump): In recurse mode print enter/leave once for the + whole makefile. + (output_init): Initialize this processes stdio as well as child's. + + * vmsjobs.c: Reformat to be closer to convention. + +2013-09-12 Paul Smith + + Rework output to handle synchronization and directory logging more + reliably. + + * output.c: New file. Implement lazy synchronization and + directory logging so that we manage them "just in time", and the + destination of the output is set via a global state variable. + * output.h: New file. + * function.c (func_shell_base): Ensure the output is set up before + running a shell command, in case it writes to stderr. + (func_error): Use outputs() to generate output. + * job.h (struct child): Add struct output to track the child's output. + * job.c: Use struct output in the child structure to track output. + (child_out, sync_init, assign_child_tempfiles, pump_from_tmp) + (acquire_semaphore, release_semaphore, sync_output): Move most of + the output_sync handling to output.c. + (child_error): Set output, then use simple message() and error() + not _s versions. + * main.c (log_working_directory): Moved to output.c + (trace_option, decode_trace_flags) Remove. Remove support for + different trace modes; we don't use it anymore. + (die) Invoke output_close() before we exit. + * misc.c (message_s, error_s): Removed; no longer needed. + (message, error, fatal, perror_with_name, pfatal_with_name): Moved + to output.c. + * makeint.h: Remove message_s(), error_s(), and + log_working_directory(). Remove the TRACE_* macros. + * doc/make.texi: Enhance documentation for output sync, and remove + MODE assignment for --trace. + * make.1: Remove MODE assignment for --trace. + * Makefile.am: Add new files. + * NMakefile.template: Ditto. + * SMakefile.template: Ditto. + * build_w32.bat: Ditto. + * dosbuild.bat: Ditto. + * make.lnk: Ditto. + * make_nsvc_net2003.vcproj: Ditto. + * makefile.vms: Ditto. + * po/POTFILES.in: Ditto. + +2013-08-22 Petr Machata + + * function.c (func_shell_base): Get rid of any avoidable limit on + stack size for processes spawned via $(shell). + +2013-07-22 Paul Smith + + * implicit.c (pattern_search): Use PARSE_SIMPLE_SEQ() even for + non-second expansion prerequisites, to handle globbing in patterns. + Fixes Savannah bug #39310. + + * dep.h (PARSE_SIMPLE_SEQ): Macro for simple file sequence parsing. + * default.c (set_default_suffixes): Use it. + * file.c (split_prereqs): Ditto. + * main.c (main): Ditto. + * read.c (eval): Ditto. + * rule.c (install_pattern_rule): Ditto. + * file.c (split_prereqs): Use PARSEFS_NONE instead of 0. + +2013-07-21 Paul Smith + + Cleanups detected by cppcheck. Fixes Savannah bug #39158. + * arscan.c (ar_scan): Reduce the scope of local variables. + * dir.c (vms_hash): Ditto. + (find_directory): Ditto. + (file_impossible_p): Ditto. + * expand.c (variable_expand_string): Ditto. + * function.c (func_sort): Ditto. + (func_and): Ditto. + * job.c (reap_children): Ditto. + (exec_command): Ditto. + * main.c (main): Ditto. + * misc.c (collapse_continuations): Ditto. + * read.c (eval): Ditto. + (parse_file_seq): Ditto. + * vpath.c (gpath_search): Ditto. + (selective_vpath_search): Ditto. + * job.c (is_bourne_compatible_shell): Simplify for non-Windows systems. + * remake.c (f_mtime): Remove duplicate test. + * signame.c (strsignal): Fix bogus conditional. + + * job.c (assign_child_tempfiles): Assign OUTFD to -1 for safety. + (start_job_command): Don't test output_sync and sync_cmd: redundant. + Changes suggested by Frank Heckenbach . + +2013-07-14 Paul Smith + + * filedef.h (update_status): Convert UPDATE_STATUS from a char to + an enumeration. Some systems declare "char" to be "unsigned" + which broke the code (which expected to be able to use -1 as a + flag). Using magic values was unpleasant, so rather than just + force "signed char" I reworked it to use an enum. + + * dep.h (update_goal_chain): Return an update_status value not int. + * remake.c (touch_file): Ditto. + (update_goal_chain): Track the update_status enum. + + * file.c (enter_file): Use new enumeration values with update_status. + (remove_intermediates): Ditto. + (print_file): Ditto. + * commands.c (execute_file_commands): Ditto. + * job.c (reap_children): Ditto. + (start_job_command): Ditto. + (start_waiting_job): Ditto. + * main.c (main): Ditto. + * remake.c (update_file): Ditto. + (complain): Ditto. + (update_file_1): Ditto. + (notice_finished_file): Ditto. + (remake_file): Ditto. + * vmsjobs.c (vmsHandleChildTerm): Ditto. + +2013-07-09 Paul Smith + + * implicit.c (pattern_search): Keep a local copy of the number of + deps in deplist: the global max might change due to recursion. + Fixes a bug reported by Martin d'Anjou . + +2013-06-28 Paul Smith + + * misc.c (set_append_mode): Set the O_APPEND flag on a file descriptor. + (open_tmpfd): Set append mode on the temporary file descriptor. + * main.c (main): Set append mode on stdout and stderr. + * makeint.h (set_append_mode): Declare it. + +2013-06-22 Eli Zaretskii + + * build_w32.bat (LinkGCC): Prevent a comment from being displayed + at build time. + + * job.c (construct_command_argv_internal) [WINDOWS32]: Use + case-insensitive comparison with internal commands of non-Unix + shells. + + * main.c (find_and_set_default_shell): Don't use file_exists_p or + dir_file_exists_p, as those call readdir, which can fail if PATH + includes directories with non-ASCII characters, and that would + cause Make to fail at startup with confusing diagnostics. See + https://sourceforge.net/mailarchive/message.php?msg_id=30846737 + for the details. + +2013-06-22 Paul Smith + + Improve performance by using a character map to determine where we + want to stop searching strings, rather than discrete comparisons. + + * read.c (find_char_unquote): Pass a stop map instead of various + flags and use that to check when to stop parsing the string. + (eval): Use the new find_char_unquote() calling signature. + (remove_comments): Ditto. + (unescape_char): Ditto. + (find_percent_cached): Ditto. + (parse_file_seq): Use a stop-map flag. + * main.c (stopchar_map): Character map definition. + (initialize_stopchar_map): Initialize the map definition. + (main): Invoke the map initialization function. + * misc.c (end_of_token_w32): Remove unused function. + * dir.c (dosify): Use STOP_SET to check for stop chars. + * main.c (main): Ditto. + * misc.c (end_of_token): Ditto. + * function.c (subst_expand): Ditto. + (func_notdir_suffix): Ditto. + (func_basename_dir): Ditto. + (abspath): Ditto. + * job.c (is_bourne_compatible_shell): Ditto. + * variable.c (parse_variable_definition): Ditto. + * read.c (eval): Ditto. + (conditional_line): Ditto. + (find_percent_cached): Ditto. + * dep.h (PARSE_FILE_SEQ): Update function declaration. + * default.c (set_default_suffixes): Update PARSE_FILE_SEQ() call. + * file.c (split_prereqs): Ditto. + * function.c (string_glob): Ditto. + * implicit.c (pattern_search): Ditto. + * rule.c (install_pattern_rule): Ditto. + * main.c (main): Ditto. + +2013-06-21 Paul Smith + + * main.c (verify_flag): Global variable to determine whether to + verify the database or not. + (decode_debug_flags): If debug mode, enable verify_flag. + (main): If MAKE_MAINTAINER_MODE, enable verify_flag, otherwise not. + (die): Only verify the database if verify_flag is set. + * file.c (enter_file): Don't check caching unless verify_flag. + * makeint.h: Export verify_flag. + +2013-05-27 Paul Smith + + * variable.c (define_automatic_variables): Create a new variable + MAKE_HOST. + +2013-05-27 Hartmut Becker + + * function.c (func_shell_base) [VMS]: Support VMS. + * makefile.com [VMS]: Ditto. + * makefile.vms [VMS]: Ditto. + * makeint.h [VMS]: Ditto. + * vmsjobs.c [VMS]: Ditto. + * job.h: Define RECORD_SYNC_MUTEX() when OUTPUT_SYNC is not set. + * load.c (unload_file): Fix signature if MAKE_LOAD is not set. + +2013-05-26 Paul Smith + + * remake.c (f_mtime): Ensure that archive file names are in the + string cache. Fixes Savannah bug #38442. + + * read.c (readline): To be safe, move the entire buffer if we + detect a CR. Fixes Savannah bug #38945. + + * job.c (new_job): Compare OUT to the beginning of the OUT + var/function, not IN. Fixes Savannah bug #39035. + +2013-05-22 Paul Smith + + * main.c (switches[]): Order switches so simple flags all come first. + (define_makeflags): Rework to make option passing more + reliable and the code less tricksy. Ensure simple flags are kept + in the initial batch of flags. Do not allow any flags with + options in that batch. If there are only non-simple flags MAKEFLAGS + begins with ' '. + (print_data_base): Print the version. Fixes part of Savannah #35336. + + * read.c (eval_buffer): Initialize lineno. + +2013-05-18 Alexey Pavlov (tiny change) + + * w32/Makefile.am (libw32_a_SOURCES): Add compat/posixfcn.c. + + * configure.ac (OUTPUT_SYNC): Define for mingw32 target. + + * job.c (construct_command_argv_internal) + [WINDOWS32]: Add "move". Fixes Savannah bug #30714. + + * guile.c: Move inclusion of makeint.h before gnumake.h. This + order must be observed when building Make, because gnumake.h must + be included with GMK_BUILDING_MAKE defined, which makeint.h + already does. Otherwise, the linker will look for, and fail to + find, gmk_* functions in some external dynamic library. + +2013-05-17 Benno Schulenberg + + * main.c (decode_output_sync_flags): Fix output message. + * read.c (EXTRANEOUS): Ditto. + (record_files): Ditto. + * remake.c (update_file_1): Ditto. + +2013-05-17 Eli Zaretskii + + * main.c (prepare_mutex_handle_string): Define conditioned on + OUTPUT_SYNC. + + * build_w32.bat: Copy config.h.W32 to config.h regardless of + whether or not we are building from SCM. + +2013-05-17 Paul Smith + + * configure.ac: Update version to 3.99.90. + * NEWS: Ditto. + + * Source (*.[ch]): Remove TABs, use GNU coding styles. + + * ALL: Update copyright. + + * hash.c (CALLOC): Use xcalloc() to handle out of memory errors. + + * makeint.h: Prototype new unload_file() function. + * load.c (unload_file): Create a function to unload a file. + (struct load_list): Type to remember loaded objects. + (loaded_syms): Global variable of remembered loaded objects so we + can unload them later. We don't have to remove from the list + because the only time we unload is if we're about to re-exec. + (load_object): Remove unneeded extra DLP argument. + (load_file): Remove unneeded extra DLP argument. + * filedef.h (struct file): Remove the DLP pointer and add the + LOADED bit flag. Saves 32/64 bytes per file, as this pointer is + almost never needed. + * read.c (eval): Set the new LOADED bit flag on the file. + * file.c (rehash_file): Merge the loaded bitfield. + * commands.c (execute_file_commands): Call unload_file() instead + of dlclose() directly. + +2013-05-14 Paul Smith + + * doc/make.texi (Loaded Object API): Document the requirement for + the plugin_is_GPL_compatible symbol. + * load.c (load_object): Check for plugin_is_GPL_compatible symbol. + +2013-05-13 Paul Smith + + * filedef.h (struct file): Add a builtin flag. + * file.c (enter_file): Unset the builtin flag. + (rehash_file): Ditto. + (print_file): Don't print builtin files if we've omitted them. + * default.c (undefine_default_variables): New function: go through + the default variables and undefine them. + (set_default_suffixes): Mark these suffix rules as builtin. + * makeint.h: Prototype. + * main.c (main): Handle addition of -r and -R to MAKEFLAGS in the + makefile. Fixes Savannah bug #20501. + + * main.c (define_makeflags): Assign o_env_override level to + MAKEFLAGS to ensure it's set even in the presence of -e. + Fixes Savannah bug #2216. + + * makeint.h (TRACE_NONE, TRACE_RULE, TRACE_DIRECTORY): Define + constants for the trace mode. + * main.c: Add new --trace mode parsing. + (decode_trace_flags): New function. + (decode_switches): Call it. + (define_makeflags): Fix a bug with long-name options. + * misc.c (fatal): Remove special output-sync handling. + * make.1: Document new --trace mode flags. + * doc/make.texi (Options Summary): Ditto. + +2013-05-11 Eli Zaretskii + + * job.c (child_out): Output the newline following the message + before fllush-ing the stream. Avoids displaying the following + failure message, which goes to stderr, on the same line. + +2013-05-06 Eli Zaretskii + + * gnumake.h (GMK_EXPORT) [_WIN32]: Move the dllexport declaration + here from makeint.h. + + * makeint.h (GMK_BUILDING_MAKE) [WINDOWS32]: Define before + including gnumake.h. + + * doc/make.texi (Loaded Object Example): Add a note about building + shared objects on MS-Windows. + +2013-05-05 Paul Smith + + * makeint.h (OUTPUT_SYNC_LINE, OUTPUT_SYNC_RECURSE): Rename + output-sync options "job" to "line" and "make" to "recurse". + * main.c (decode_output_sync_flags): Ditto. + * job.c (reap_children): Ditto. + (start_job_command): Ditto. + * make.1: Ditto. + * doc/make.texi (Parallel Output): Ditto. + + * job.c (child_out): Write newlines explicitly, and don't do + anything if the message is empty. + (sync_output): Put working dir messages around stdout AND stderr. + (start_job_command): Move the tmp file assignment earlier. After + we do it, write the command line to the temp file to get the order + correct. + + * misc.c (message): Remove special handling for output_sync. + (error): Ditto. + +2013-05-04 Paul Smith + + * loadapi.c (gmk_alloc): New function. + * gnumake.h: Add gmk_alloc(). Clean GMK_EXPORT a bit to avoid MAIN. + * makeint.h (GMK_EXPORT): New handling, vs. MAIN. + * doc/make.texi (Loaded Object API): Add information on the memory + handling functions. + (Loaded Object Example): Create an example. + + * job.c (pump_from_tmp): (Rename) Write to stdout/stderr using + FILE* rather than fd. It's not a good idea to mix and match. + +2013-05-04 Eli Zaretskii + + * makeint.h (ftruncate) [_MSC_VER]: Redirect to _chsize. + (_S_ISDIR): If not defined (MinGW64), define to S_ISDIR. + +2013-05-04 Paul Smith + + * job.c (child_out): Handle EINTR and incomplete write scenarios. + (sync_init): New function: separate the initialization code. + (assign_child_tempfiles): Remove truncation from this function, + (sync_output): and add it here after output is generated. + (reap_children): Always call sync_output() in case output_sync was + reset after the child started, due to error. + (start_job_command): Create new sync_cmd variable. Use new method + for initializing the handle. + If we're not syncing the output be sure any output we've saved is + dumped immediately before starting the child. + +2013-05-04 Eli Zaretskii + + * job.c (start_job_command): Make the condition for creating a + temporary output file be identical to the Posix code branch. + Suggested by Frank Heckenbach . + +2013-05-03 Eli Zaretskii + + * w32/subproc/sub_proc.c: Include makeint.h. Remove a private + incompatible prototype of xmalloc. + (batch_file_with_spaces): New function, detects Windows batch + files whose names include whitespace characters. + (process_begin): If exec_name is a batch file with whitespace + characters in its name, pass NULL as the first argument to + CreateProcess. This avoids weird failures due to buggy quoting by + CreateProcess. For the details, see the discussion starting at + http://lists.gnu.org/archive/html/make-w32/2013-04/msg00008.html. + + * load.c (load_object, load_file): Accept an additional argument + DLP and return in it a pointer that can be used to unload the + dynamic object. + + * read.c (eval): Call load_file with an additional argument, and + record the pointer returned there in the 'struct file' object of + dynamic objects in that object's 'struct file'. + + * commands.c (execute_file_commands): Unload dynamic objects + before remaking them, to avoid failure to remake if the OS doesn't + allow overwriting objects that are in use. + + * filedef.h (struct file): New member dlopen_ptr. + + * gnumake.h (GMK_EXPORT): Define to dllexport/dllimport + decorations for Windows and to nothing on other platforms. + (gmk_eval, gmk_expand, gmk_add_function): Add GMK_EXPORT qualifier + to prototypes. + + * makeint.h (MAIN): Define before including gnumake.h, to give + correct dllexport decorations to exported functions. + (load_file): Adjust prototype. + + * loadapi.c: Don't include gnumake.h, since makeint.h already + includes it, and takes care of defining MAIN before doing so. + + * build_w32.bat (LinkGCC): Produce an import library for functions + exported by Make for loadable dynamic objects. + + * w32/compat/posixfcn.c (dlclose): New function. + + * w32/include/dlfcn.h (dlclose): Add prototype. + +2013-05-01 Eli Zaretskii + + * job.c (start_job_command) [WINDOWS32]: Make the same fix for + MS-Windows as the previous commit did for Posix platforms. + (construct_command_argv_internal): Don't treat a backslash as an + escape character before whitespace, if the shell is not a Posix + shell. For the description of the problem, see + http://lists.gnu.org/archive/html/make-w32/2013-04/msg00014.html. + +2013-05-01 Paul Smith + + * job.c (start_job_command): Don't redirect output for recursive + make jobs, unless we're in makefile synchronization mode. + +2013-04-30 Stefano Lattarini (tiny change) + + build: enable the 'silent-rules' automake options + + * configure.ac (AM_INIT_AUTOMAKE): Here. The future major Automake + version 2.0 (ETA about one, one and half year from now) will enable + it by default, so better prepare ourselves. + +2013-04-30 Stefano Lattarini (tiny change) + + build: require Autoconf >= 2.62 and Automake >= 1.11.1 + + Older versions of those tools should be considered fully obsolete. + Also, GNU make already requires Gettext >= 0.18.1, which has been + released six months after Automake 1.11.1 and two years after + Autoconf 2.62; so the new requirement shouldn't be problematic + for people already bootstrapping GNU make from the Git repository. + + * configure.ac (AC_PREREQ): Require Autoconf 2.62 or later. + (AM_INIT_AUTOMAKE): Require Automake 1.11.1 or later (1.11 had + some serious bugs, and should not be used). + +2013-04-30 Stefano Lattarini (tiny change) + + build: get rid of 'HAVE_ANSI_COMPILER' C preprocessor conditional + + GNU make already assume C89 or later throughout the codebase, and + that preprocessor conditional was no longer used anyway. + + * configure.ac: Remove AC_DEFINE of HAVE_ANSI_COMPILER. + * config.ami.template: Remove #define of HAVE_ANSI_COMPILER. + * config.h-vms.template: Likewise. + * config.h.W32.template: Likewise. + * configh.dos.template: Likewise. + +2013-04-30 Stefano Lattarini (tiny change) + + cosmetics: fix few innocuous typos + + Most of these were found using Lucas De Marchi's 'codespell' tool. + + * ChangeLog: Fix minor typos. + * ChangeLog.2: Likewise. + * README.Amiga: Likewise. + * TODO.private: Likewise. + * function.c: Likewise. + * glob/glob.h: Likewise. + * job.c: Likewise. + * main.c: Likewise. + * readme.vms: Likewise. + * remake.c: Likewise. + * tests/ChangeLog: Likewise. + * tests/NEWS: Likewise. + * tests/README: Likewise. + * tests/scripts/variables/private: Likewise. + * vmsdir.h: Likewise. + * signame.c: Likewise. While at it, improve line wrapping in the + touched comment. + +2013-04-29 Eli Zaretskii + + * w32/include/dlfcn.h: New file. + + * w32/compat/posixfcn.c: Include dlfcn.h. + (dlopen, dlerror, dlsym) [MAKE_LOAD]: New functions, in support of + dynamic loading. + + * config.h.W32.template (MAKE_LOAD): Define. + + * load.c (load_object) [HAVE_DOS_PATHS]: Support backslashes and + drive letters in file names of dynamic objects. + + * job.c (construct_command_argv_internal) [WINDOWS32]: Return + right after generating new_argv for one_shell case. This fixes + the Windows build for both Unixy shell and stock Windows shells. + +2013-04-28 Eli Zaretskii + + * dir.c (local_stat) [WINDOWS32]: Use the wrapper on MS-Windows. + If the argument ends in "dir/.", make sure the parent dir exists + and is indeed a directory. Fixes Savannah bug #37065. + +2013-04-28 Paul Smith + + * makeint.h (message_s, error_s): Functions that print to strings + rather than directly to files. + * misc.c (message_s, error_s): Create them. + * job.c (child_error): Print error messages to the output sync + logs, if one exists, rather then directly to the terminal. + (reap_children): Move the per-line sync after child_error(). + + * configure.ac: Remove support for pre-ANSI variadic function calls. + * makeint.h: Ditto. + * misc.c: Ditto. + * config.ami.template: Ditto. + * config.h-vms.template: Ditto. + * config.h.W32.template: Ditto. + * configh.dos.template: Ditto. + + Implement a "per-job" output synchronization option. + + * main.c (decode_output_sync_flags): Recognize the new option. + * makeint.h (OUTPUT_SYNC_JOB): Add new values for "job" + * job.c (assign_child_tempfiles): In per-job mode, truncate the + temp file for re-use by the next job. + (sync_output): Don't close the temp files as we may still use them. + (free_child): Close the temp files here as we definitely don't + need them. + (new_job): In per-job output mode, sync_output() after each job. + * job.h (struct child): Avoid ifdefs. + * make.1: Add new options to the man page. + * doc/make.texi (Parallel Output): Break documentation on input + and output into separate sections for readability. Document the + new "job" and "none" modes. + +2013-04-27 Paul Smith + + * job.c (construct_command_argv_internal): Fix oneshell support + for non-POSIX-sh shells. + + * load.c (load_object): Extract all POSIX-isms into a separate + function for portability. + (load_file): Check the .LOADED variable first and don't invoke + load_object() if it's already been loaded. + +2013-04-27 Eli Zaretskii + + * read.c (record_files): Pay attention to .ONESHELL in MS-Windows. + + * job.c (construct_command_argv_internal): Support .ONESHELL on + MS-Windows, when the shell is not a Unixy shell. + +2013-04-27 Eli Zaretskii + + * job.c: Fix compilation error on GNU/Linux due to "label at end + of compound statement". + +2013-04-27 Frank Heckenbach (tiny change) + + * job.c (sync_output): Don't discard the output if + acquire_semaphore fails; instead, dump the output unsynchronized. + +2013-04-27 Eli Zaretskii + + Support --output-sync on MS-Windows. + * w32/compat/posixfcn.c: New file, with emulations of Posix + functions and Posix functionality for MS-Windows. + + * w32/subproc/sub_proc.c: Include io.h. + (process_noinherit): New function, forces a file descriptor to not + be inherited by child processes. + (process_easy): Accept two additional arguments, and use them to + set up the standard output and standard error handles of the child + process. + + * w32/include/sub_proc.h (process_easy): Adjust prototype. + (process_noinherit): Add prototype. + + * read.c [WINDOWS32]: Include windows.h and sub_proc.h. + + * makeint.h (LOCALEDIR) [WINDOWS32}: Define to NULL if not + defined. This is needed because the MS-Windows build doesn't have + a canonical place for LOCALEDIR. + (WIN32_LEAN_AND_MEAN) [WINDOWS32]: Define, to avoid getting from + windows.h header too much stuff that could conflict with the code. + + * main.c : New static variable. + : Add support for "--sync-mutex" switch. + (decode_output_sync_flags): Decode the --sync-mutex= switch. + (prepare_mutex_handle_string) [WINDOWS32]: New function. + (main): Add "output-sync" to .FEATURES. + + * job.h (CLOSE_ON_EXEC) [WINDOWS32]: Define to call + process_noinherit. + (F_GETFD, F_SETLKW, F_WRLCK, F_UNLCK, struct flock) [WINDOWS32]: + New macros. + (RECORD_SYNC_MUTEX): New macro, a no-op for Posix platforms. + (sync_handle_t): New typedef. + + * job.c : Change type to sync_handle_t. + (FD_NOT_EMPTY): Seek to the file's end. Suggested by Frank + Heckenbach . + (pump_from_tmp_fd) [WINDOWS32]: Switch to_fd to binary mode for + the duration of this function, and then change back before + returning. + (start_job_command) [WINDOWS32]: Support output_sync mode on + MS-Windows. Use a system-wide mutex instead of locking + stdout/stderr. Call process_easy with two additional arguments: + child->outfd and child->errfd. + (exec_command) [WINDOWS32]: Pass two additional arguments, both + -1, to process_easy, to adjust for the changed function signature. + + * function.c (windows32_openpipe) [WINDOWS32]: This function now + returns an int, which is -1 if it fails and zero otherwise. It + also calls 'error' instead of 'fatal', to avoid exiting + prematurely. + (func_shell_base) [WINDOWS32]: Call perror_with_name if + windows32_openpipe fails, now that it always returns. This avoids + a compiler warning that error_prefix is not used in the MS-Windows + build. + + * config.h.W32.template (OUTPUT_SYNC): Define. + + * build_w32.bat: Add w32/compat/posixfcn.c to compilation and + linking commands. + +2013-04-20 Stefano Lattarini (tiny change) + + * README.git: Our autoconf input file is 'configure.ac', not + 'configure.in'. Adjust accordingly. + * build_w32.bat: Likewise. + * config.h-vms.template: Likewise. + * Makefile.DOS.template: Likewise. + +2013-04-16 Paul Smith + + * misc.c (open_tmpfd): Add a new function that returns a temporary + file by file descriptor. + (open_tmpfile): Move here from main.c. + * job.c (assign_child_tempfiles): Use the new open_tmpfd(). + +2013-04-15 Paul Smith + + * makeint.h (OUTPUT_SYNC_TARGET, OUTPUT_SYNC_MAKE): Rename. + * job.c (start_job_command): Use new constants. + * main.c: New -O argument format. + + * doc/make.texi (Options Summary): Document the argument to -O. + * make.1: Ditto. + + * main.c (define_makeflags): Don't add space between a single-char + option and its argument. + +2013-04-06 Paul Smith + + * doc/make.texi (Implicit Variables): Clarify LDFLAGS vs. LDLIBS. + Fixes Savannah bug #37970. + + * remake.c (check_dep): Reconsider files waiting on prerequisites, + as they may have finished. Fixes Savannah bug #37703. + +2013-02-28 Paul Smith + + * function.c (func_realpath): On Solaris (at least) realpath() can + fail due to EINTR, so loop it. Fixes Savannah bug #38420. + +2013-02-25 Paul Smith + + Add a proposed supported API for GNU make loaded objects. + + * doc/make.texi (Loaded Object API): Document it. + * Makefile.am (make_SOURCES): Add new loadapi.c. + * dep.h: Remove eval_buffer(); moved to loadapi.c:gmk_eval(). + * read.c (eval_buffer): Change eval_buffer() signature. + * main.c (main): Change eval_buffer() signature. + * variable.h (define_new_function): Change func_ptr signature. + * load.c (SYMBOL_EXTENSION): Change the extension. + * loadapi.c: Implement the new API. + * gnumake.h (gmk_eval): New function prototype. + (gmk_expand) Ditto. + (gmk_add_function) Ditto. + * gmk-default.scm (gmk-eval): Remove: now implemented in guile.c. + * guile.c (guile_expand_wrapper): Use gmk_expand() + (guile_eval_wrapper): Implement eval here to avoid double-expansion. + (guile_define_module): Define gmk-eval. + (func_guile): Use new func_ptr calling model. + (guile_gmake_setup): Use gmk_add_function() to declare $(guile ...) + * function.c (function_table_entry): Provide alternative func_ptr. + (func_eval): New signature for eval_buffer(); + (function_table_init): New initialization for function_table_entry. + (expand_builtin_function): Support alternative invocation signature. + (define_new_function): Ditto. + +2013-01-20 Paul Smith + + * gnumake.h: New file to contain externally-visible content. + * makeint.h: Include gnumake.h. Move gmk_floc type to gnumake.h. + * Makefile.am (include_HEADERS): Install the gnumake.h header. + + * makeint.h: Change struct floc to gmk_floc typedef. + * Many: Use the new typedef. + + * make.h: Rename to makeint.h. + * Many: Use the new name makeint.h. + +2013-01-19 Paul Smith + + * doc/make.texi (load Directive): Update to discuss location of + loaded object file. + (Remaking Loaded Objects): Document remaking of loaded objects. + + * main.c (main): Rename READ_MAKEFILES to READ_FILES. + * read.c: Change READ_MAKEFILES to READ_FILES since it now + contains loaded object files as well. + (read_all_makefiles): Ditto. + (eval_makefile): Ditto. + (eval): Add any loaded file to the READ_FILES list, so that it + will be considered for re-build. + + * load.c (load_file): Return the simple filename (no symbol) in + the LDNAME argument (now a const char **). + This filename should no longer have "./" prepended: modify the + function to always check the current directory if the name has no + "/", before using the normal methods. + * make.h: Change the load_file() prototype. + + * README.git: Add a bit more documentation on Git workflow & rules. + +2013-01-13 Paul Smith + + * main.c (main): Restore all make flags after re-exec is complete. + Fixes Savannah bug #38051. + +2013-01-12 Paul Smith + + Convert CVS archive to Git. + + * configure.in: Rename to configure.ac. + * README.cvs: Rename to README.git and rework for Git. + * maintMakefile: Use git clean for cleanup. + * ChangeLog: Use new Git repository URL. + * ChangeLog.2: Ditto. + * Makefile.am: Change documentation for Git + * Makefile.DOS.template: Ditto. + * README.template: Ditto. + * build_w32.bat: Ditto. + * prepare_w32.bat: Ditto. + * .cvsignore: Rename to .gitignore, and change to Git format. + +2012-12-08 Eli Zaretskii + + * job.c (create_batch_file): Fix last change: always increment the + counter of batch files before trying to use it. + +2012-12-07 Eli Zaretskii + + * job.c (construct_command_argv_internal): Remove " from + sh_chars_dos[]. Ignore an escaped backslash inside a string + quoted with "..". This lifts the 4KB or 8KB command-line length + limitation imposed by the Windows shells when a command uses quoted + strings, because we now don't call the shell in that case. + + * job.c (create_batch_file): Declare the counter of batch files + static, to avoid having 2 jobs using the same file name and + stepping on each other's toes. When all 64K names are used up, + make one more loop looking for slots that became vacant. This + avoids leaving behind temporary batch files in the temporary + directory, which happens frequently on a fast machine when using + parallel builds. + (reap_children): Add debug message for when removal of a temporary + batch file fails. + +2012-10-29 Paul Smith + + New feature: "load" directive for dynamically-loaded objects. + + * NEWS: Document new "load" directive. + * doc/make.texi (Extending make): New chapter on extensions to make. + * configure.in: Check for dlopen/dlsym/dlerror and -ldl. + * Makefile.am (make_SOURCES): Add new file load.c. + * make.h: Prototype for load_file(). + * main.c (main): Add "load" to .FEATURES if it's available. + * read.c (eval): Parse "load" and "-load" directives. + +2012-09-29 Paul Smith + + * configure.in: Require a new version of gettext (1.18.1). + Fixes Savannah bug #37307. + +2012-09-09 Paul Smith + + * configure.in (bsd_signal): Define _GNU_SOURCE, a la make.h. + Fixes Savannah bug #32247. + + * remake.c (update_file_1): Force intermediate files to be + considered, not pruned, if their non-intermediate parent needs to + be remade. Fixes Savannah bug #30653. + + * job.c (construct_command_argv_internal): Keep the command line + on the heap for very long lines. Fixes Savannah bug #36451. + + * function.c (func_realpath): BSD realpath(3) doesn't fail if the + file does not exist: use stat. Fixes Savannah bug #35919. + + * file.c (expand_deps): Duplicate the current variable buffer, not + the old pointer. Fixes Savannah bug #36925. + + * read.c (eval): If we detect an initial UTF-8 BOM, skip it. + Fixes Savannah bug #36529. + (record_target_var): Remove unused variable "fname". + (eval): Use the correct pointer when adding to the variable buffer. + Fixes Savannah bug #36106. + +2012-09-09 Eli Zaretskii + + * read.c (unescape_char): Fix a thinko in the last change. + +2012-09-09 Paul Smith + + * default.c (default_variables): Use a correct default LIBPPATERNS + for MacOS. Fixes Savannah bug #37197. + + * read.c (record_files): Reset the default macro values if .POSIX + is set. Fixes Savannah bug #37069. + (parse_file_seq): Break out of an infinite loop if we're not + making progress when parsing archive references. + +2012-09-01 Eli Zaretskii + + * README.W32.template: Update for job-server and Guile support. + + * read.c (unescape_char): Advance 'p' after copying the unescaped + characters. Otherwise the backslashes are incorrectly erased from + the original string. + +2012-03-05 Paul Smith + + Update copyright notices to use year ranges, as allowed by + clarifications in the GNU Maintainer's Manual. + +2012-03-04 Paul Smith + + * read.c (unescape_char): New function to remove escapes from a char. + (record_files): Call it on the dependency string to unescape ":". + Fixes Savannah bug #12126 and bug #16545. + + * make.h (CSTRLEN): Determine the length of a constant string. + * main.c: Use the new macro. + * read.c: Ditto. + * variable.h: Ditto. + * function.c: Simplify checks for function alternatives. + + * expand.c (variable_append): If the current set is local and the + next one is not a parent, then treat the next set as + local as well. Fixes Savannah bug #35468. + +2012-03-03 Paul Smith + + * acinclude.m4 (AC_STRUCT_ST_MTIM_NSEC): Add support for AIX 5.2+ + nanosecond timestamps. Fixes Savannah bug #32485. + + Convert uses of `foo' for quoting to 'foo' to reflect changes in + the GNU Coding Standards. Fixes Savannah bug #34530. + + * job.c (construct_command_argv_internal): In oneshell we need to + break the SHELLFLAGS up for argv. Fixes Savannah bug #35397. + + * function.c (func_filter_filterout): Recompute the length of each + filter word in case it was compressed due to escape chars. Don't + reset the string as it's freed. Fixes Savannah bug #35410. + + * misc.c (collapse_continuations): Only use POSIX-style + backslash/newline handling if the .POSIX target is set. + Addresses Savannah bug #16670 without backward-incompatibility. + * NEWS: Document behavior change. + * doc/make.texi (Splitting Lines): New section describing how to + use backslash/newline to split long lines. + +2012-02-26 Paul Smith + + * implicit.c (pattern_search): Check the stem length to avoid + stack overflows in stem_str. Fixes Savannah bug #35525. + +2012-02-03 Eli Zaretskii + + * w32/subproc/sub_proc.c (proc_stdin_thread, proc_stdout_thread) + (proc_stderr_thread, process_pipe_io): Ifdef away unused + functions. + + * w32/subproc/w32err.c (map_windows32_error_to_string) [_MSC_VER]: + Don't use TLS storage for szMessageBuffer. Ifdef away special + code for handling Winsock error codes. Make the function return a + `const char *'. Suggested by Ozkan Sezer. Fixes Savannah bug #34832. + +2012-01-29 Paul Smith + + * gmk-default.scm (to-string-maybe): Variables map to empty strings. + In Guile 2.0, (define ...) results in a variable object so make + sure that maps to an empty string in make. + + * variable.c (parse_variable_definition): New POSIX assignment ::= + Take a struct variable to return more information after parsing. + (assign_variable_definition): New parse_variable_definition() call. + * variable.h: New declaration of parse_variable_definition(). + * read.c (do_define): New parse_variable_definition() call. + (parse_var_assignment): Ditto. + (get_next_mword): Parse ::= as a variable assignment. + * doc/make.texi (Flavors): Describe the new ::= syntax. + * NEWS: Mention the ::= operator. + + * variable.h (struct variable): Rearrange elts to reduce struct size. + + * function.c (func_file): Create a new function, $(file ...) + * doc/make.texi (File Function): Document the $(file ..) function. + * NEWS: Announce it. + + * gmk-default.scm (to-string-maybe): Use a more portable way to + test for unprintable characters. + * configure.in [GUILE]: Guile 1.6 doesn't have pkg-config + * build_w32.bat: Ditto. + +2012-01-28 Eli Zaretskii + + * config.h.W32.template: Update from config.h.in. + + Support a Windows build with Guile. + + * README.W32.template: Update with instructions for building with + Guile. + + * build_w32.bat: Support building with Guile. + + * make.h [HAVE_STDINT_H]: Include stdint.h. + + * main.c (main, clean_jobserver): Move declarations of variables + not used in the WINDOWS32 build to the #else branch, to avoid + compiler warnings. + + Fix failures on MS-Windows when Make's standard handles are invalid. + This can happen when Make is invoked from a GUI application. + + * w32/subproc/sub_proc.c (process_init_fd): Don't dereference + pproc if it is a NULL pointer. + (process_begin, process_cleanup): Don't try to close pipe handles + whose value is INVALID_HANDLE_VALUE. + (process_easy): Initialize hIn, hOut, and hErr to + INVALID_HANDLE_VALUE. If DuplicateHandle fails with + ERROR_INVALID_HANDLE, duplicate a handle for the null device + instead of STD_INPUT_HANDLE, STD_OUTPUT_HANDLE or + STD_ERROR_HANDLE. Don't try to close pipe handles whose value is + INVALID_HANDLE_VALUE. + + * function.c (windows32_openpipe): Initialize hIn and hErr to + INVALID_HANDLE_VALUE. If DuplicateHandle fails with + ERROR_INVALID_HANDLE, duplicate a handle for the null device + instead of STD_INPUT_HANDLE or STD_ERROR_HANDLE. Fix indentation. + Don't try to close handles whose value is INVALID_HANDLE_VALUE. + +2012-01-25 Eli Zaretskii + + * function.c (define_new_function): Fix format strings in calls to + `fatal'. + +2012-01-17 Paul Smith + + * guile.c (func_guile): Handle NULL returns from Guile. + +2012-01-16 Paul Smith + + * make.h (PATH_SEPARATOR_CHAR): Allow resetting for crosscompiling + for Windows. Patch by Chris Sutcliffe + Fixes Savannah bug #34818. + +2012-01-15 Paul Smith + + * variable.h: Prototype an interface for defining new make functions. + * function.c (define_new_function): Define it. + (func_guile): Remove the "guile" function. + (function_table_init): Ditto. + * guile.c (func_guile): Add the "guile" function here. + (setup_guile): Call define_new_function() to define it. + (guile_eval_string): Obsolete. + + * all: Update copyright notices. + +2012-01-12 Paul Smith + + Support GNU Guile as an embedded extension language for GNU make. + + * NEWS: Note the new Guile capability. + * Makefile.am (EXTRA_DIST, make_SOURCES): Add new guile source files. + (AM_CFLAGS): Add Guile compiler flags. + (guile): Add a rule for converting default SCM into a C header. + * configure.in: Add support for --with-guile. + Also, convert the entire file to properly escaped autoconf m4, and + utilize newer features such as AS_IF() and AS_CASE(). + * doc/make.texi (Guile Function): Document the GNU guile integration. + * make.h (guile_eval_string, guile_boot): Prototypes for Guile. + * main.c (main): Run guile_boot() to handle main(). + (real_main): All the previous content of main() is here. + (real_main): Add "guile" to the .FEATURES variable. + * function.c (func_guile): Call Guile. + * guile.c: New file implementing GNU make integration with GNU Guile. + * gmk-default.scm: The integration of GNU make with Guile uses + Guile itself for much of the parsing and conversion of return + types, etc. This implementation is embedded into GNU make. + * config.h-vms.template: Disable Guile support. + * config.h.W32.template: Ditto. + * configh.dos.template: Ditto. + * config.ami.template: Ditto. + * makefile.vms: Add new Guile files. + * Makefile.DOS.template: Ditto. + * Makefile.ami: Ditto. + * NMakefile.template: Ditto. + * SMakefile.template: Ditto. + * build_w32.bat: Ditto. + * dosbuild.bat: Ditto. + * make_msvc_net2001.vcproj: Ditto. + +2011-11-15 Paul Smith + + * main.c (main): Use %ld when printing DWORD values. + * job.c (new_job): Ditto. + * w32/include/sub_proc.h: Use const. + * w32/subproc/sub_proc.c (open_jobserver_semaphore): Use const. + Fixes Savannah bug #34830. Changes suggested by Ozkan Sezer. + + * configure.in (MAKE_JOBSERVER): Enable jobserver on W32 systems. + * config.h.W32.template (MAKE_JOBSERVER): Ditto. + +2011-11-14 Paul Smith + + * read.c (eval): parse_file_seq() might shorten the string due to + backslash removal. Start parsing again at the colon. + Fixes Savannah bug #33399. + +2011-11-13 Paul Smith + + * file.c (file_timestamp_cons): Match up data types to avoid warnings. + * filedef.h: Ditto. + * misc.c (concat): Ditto. + * read.c (eval): Assign value to avoid warnings. + * function.c (func_shell_base): Use fork() instead of vfork() to + avoid warnings. + * make.h (INTEGER_TYPE_SIGNED): Use <=0 to avoid warnings. + Fixes Savannah bug #34608. + + * job.c (construct_command_argv): Remove _p. + (construct_command_argv_internal): Remove _ptr. + Fixes Savannah bug #32567. + + * main.c (clean_jobserver): Don't write the free token to the pipe. + Change suggested by Tim Newsome + + * acinclude.m4 (AC_STRUCT_ST_MTIM_NSEC): Add support for Darwin. + * filedef.h (FILE_TIMESTAMP_STAT_MODTIME): Ditto. + Patch provided by Troy Runkel + +2011-10-11 Troy Runkel + + * config.h.W32: Enable job server support for Windows. + * main.c [WINDOWS32]: Include sub_proc.h + (main): Create a named semaphore to implement the job server. + (clean_jobserver): Free the job server semaphore when make is finished. + * job.c [WINDOWS32]: Define WAIT_NOHANG + (reap_children): Support non-blocking wait for child processes. + (free_child): Release job server semaphore when child process finished. + (job_noop): Don't define function on Windows. + (set_child_handler_action_flags): Don't define function on Windows. + (new_job): Wait for job server semaphore or child process termination. + (exec_command): Pass new parameters to process_wait_for_any. + * w32/include/sub_proc.h [WINDOWS32]: New/updated EXTERN_DECL entries. + * w32/subproc/sub_proc.c [WINDOWS32]: Added job server implementation. + (open_jobserver_semaphore): Open existing job server semaphore by name. + (create_jobserver_semaphore): Create new job server named semaphore. + (free_jobserver_semaphore): Close existing job server semaphore. + (acquire_jobserver_semaphore): Decrement job server semaphore count. + (release_jobserver_semaphore): Increment job server semaphore count. + (has_jobserver_semaphore): Returns whether job server semaphore exists. + (get_jobserver_semaphore_name): Returns name of job server semaphore. + (wait_for_semaphore_or_child_process): Wait for either the job server + semaphore to become signalled or a child process to terminate. + (process_wait_for_any_private): Support for non-blocking wait for child. + (process_wait_for_any): Added support for non-blocking wait for child. + (process_file_io): Pass new parameters to process_wait_for_any_private. + +2011-09-18 Paul Smith + + * main.c (main): If we're re-exec'ing and we're the master make, + then restore the job_slots value so it goes back into MAKEFLAGS + properly. See Savannah bug #33873. + + * remake.c (library_search): STD_DIRS is computed when other + static vars like buflen etc. are computed, so it must be static + as well. See Savannah bug #32511. + +2011-09-16 Paul Smith + + * maintMakefile (do-po-update): Apparently we have to avoid + certificate checks on the http://translationproject.org site now. + +2011-09-12 Paul Smith + + * read.c (eval): Ensure exported variables are defined in the + global scope. Fixes Savannah bug #32498. + +2011-09-11 Paul Smith + + * Makefile.am (dist-hook): Remove w32/Makefile and .deps/ from the + dist file. Fixes Savannah bug #31489. + + * doc/make.texi (Complex Makefile): Add a hint about using + #!/usr/bin/make (for Savannah support request #106459) + +2011-09-02 Paul Smith + + * remake.c (touch_file): If we have both -n and -t, -n takes + precedence. Patch from Michael Witten + +2011-08-29 Paul Smith + + * expand.c (variable_expand_string): Always allocate a new buffer + for a string we're expanding. The string we're working on can get + freed while we work on it (for example if it's the value of a + variable which modifies itself using an eval operation). + See Savannah patch #7534 for the original report by Lubomir Rintel. + +2011-06-12 Paul Smith + + * read.c (parse_file_seq): Move the check for empty members out of + the loop so we can go to the next member properly. + Another fix for Savannah bug #30612. + + * config.h-vms.template: Newer versions of VMS have strncasecmp() + Patch provided by: Hartmut Becker + +2011-05-07 Paul Smith + + * expand.c (variable_append): Add a LOCAL argument to track + whether this is the first invocation or not. If it's not and + private_var is set, then skip this variable and try the next one. + Fixes Savannah bug #32872. + + * read.c (parse_file_seq): Ensure existence checks use glob(). + +2011-05-07 Eli Zaretskii + + * job.c (construct_command_argv_internal): Don't assume shellflags + is always non-NULL. Escape-protect characters special to the + shell when copying the value of SHELL into new_line. Fixes + Savannah bug #23922. + +2011-05-02 Paul Smith + + * doc/make.texi (Special Variables): Add documentation for the new + words in .FEATURES. Fixes Savannah bug #32058. + (Flavor Function): Rewrite the section on the flavor function. + Fixes Savannah bug #31582. + + * function.c (func_sort): Use the same algorithm to count the + number of words we will get after the split, as we use to split. + Based on a patch from Matthias Hopf. Fixes Savannah bug #33125. + + * make.h: Make global variable stack_limit extern. + Fixes Savannah bug #32753. + +2011-05-01 Paul Smith + + * read.c (parse_file_seq): Don't try to invoke glob() unless there + are potential wildcard characters in the filename. Performance + enhancement suggested by Michael Meeks + +2011-04-29 Boris Kolpackov + + * read.c (eval_makefile): Delay caching of the file name until after + all the expansions and searches. + +2011-04-17 David A. Wheeler + + * doc/make.texi (Reading Makefiles): Document "!=". + (Setting): Ditto. + (Features): Ditto. + * variable.h (enum variable_flavor): New type "f_shell". + * variable.c (shell_result): Send a string to the shell and store + the output. + (do_variable_definition): Handle f_shell variables: expand the + value, then send it to the shell and store the result. + (parse_variable_definition): Parse "!=" shell assignments. + * read.c (get_next_mword): Treat "!=" as a varassign word. + * function.c (fold_newlines): If trim_newlines is set remove all + trailing newlines; otherwise remove only the last newline. + (func_shell_base): Move the guts of the shell function here. + (func_shell): Call func_shell_base(). + +2011-02-21 Paul Smith + + * strcache.c (various): Increase performance based on comments + from Ralf Wildenhues . Stop looking for + a buffer when we find the first one that fits, not the best fit. + If there is not enough free space in a buffer move it to a + separate list so we don't have to walk it again. + * make.h (NDEBUG): Turn off asserts unless maintainer mode is set. + (strcache_add_len, strcache_setbufsize): Use unsigned length/size. + * maintMakefile (AM_CPPFLAGS): Enable MAKE_MAINTAINER_MODE. + + * remake.c (complain): Move translation lookups closer to use. + +2011-02-13 Paul Smith + + * doc/make.texi: Clean up references to "static" variables and + semicolon errors. Patch from Michael Witten . + +2010-12-27 Paul Smith + + * make.1: Update the header/footer info in the man page. + +2010-11-28 Paul Smith + + * read.c (record_target_var): Don't reset v if it's the same as + the global version. Fixes Savannah bug #31743. + +2010-11-06 Paul Smith + + * variable.c (print_auto_variable): Print auto variables; ignore others. + (print_noauto_variable): Print non-auto variables; ignore others. + (print_variable_set): Allow the caller to select which type to print. + (print_target_variables): Show all the non-auto variables for a target. + + * default.c (install_default_suffix_rules): Initialize recipe_prefix. + * rule.c (install_pattern_rule): Ditto. + * read.c (record_files): Pass in the current recipe prefix. Remember + it in the struct command for these targets. + (eval): Remember the value of RECIPEPREFIX when we start parsing. + Do not remove recipe prefixes from the recipe here: we'll do it later. + * job.c (start_job_command): Remove recipe prefix characters early, + before we print the output or chop it up. + * file.c (print_file): If recipe_prefix is not standard, reset it + in -p output. Assign target variables in -p output as well. + + * commands.c (chop_commands): Max command lines is USHRT_MAX. + Set any_recurse as a bitfield. + * make.h (USHRT_MAX): Define if not set. + +2010-10-27 Paul Smith + + * commands.h (struct commands): Rearrange to make better use of + memory. Add new recipe_prefix value. + +2010-10-26 Paul Smith + + * doc/make.texi (Setting): Document the treatment of + backslash-newline in variable values. + * misc.c (collapse_continuations): Do not collapse multiple + backslash-newlines into a single space. Fixes Savannah bug #16670. + +2010-08-29 Paul Smith + + * doc/make.texi (Implicit Variables): Document LDLIBS and LOADLIBES. + Fixes Savannah bug #30807. + (Instead of Execution): Mention that included makefiles are still + rebuilt even with -n. Fixes Savannah bug #30762. + + * configure.in: Bump to 3.82.90. + + * make.h: Add trace_flag variable. + * main.c (switches): Add --trace option. + (trace_flag): Declare variable. + * job.c (start_job_command): Show recipe if trace_flag is set. + (new_job): Show trace messages if trace_flag is set. + * doc/make.texi (Options Summary): Document the new --trace option. + * make.1: Add --trace documentation. + * NEWS: Mention --trace. + + * job.c (child_error): Show recipe filename/linenumber on error. + Also show "(ignored)" when appropriate even for signals/coredumps. + * NEWS: Mention file/linenumber change. + + * main.c (main): Print version info when DB_BASIC is set. + + * job.c (construct_command_argv_internal): If shellflags is not + set, choose an appropriate default value. Fixes Savannah bug #30748. + +2010-08-27 Eli Zaretskii + + * variable.c (define_automatic_variables) [__MSDOS__ || WINDOWS32]: + Remove trailing backslashes in $(@D), $( + + * NEWS: Accidentally forgot to back out the sorted wildcard + enhancement in 3.82, so update NEWS. + Also add NEWS about the error check for explicit and pattern + targets in the same rule, added to 3.82. + + * main.c (main): Add "oneshell" to $(.FEATURES) (forgot to add + this in 3.82!) + + * read.c (parse_file_seq): Fix various errors parsing archives + with multiple objects in the parenthesis, as well as wildcards. + Fixes Savannah bug #30612. + +2010-08-10 Paul Smith + + * main.c (main): Expand MAKEFLAGS before adding it to the + environment when re-exec'ing. Fixes Savannah bug #30723. + +2010-08-07 Eli Zaretskii + + * w32/subproc/build.bat: Make all 3 cl.exe compile command lines + use the same /I switches. Fixes Savannah bug #30662. + + * function.c (func_shell) [WINDOWS32]: Reset just_print_flag + around the call to construct_command_argv, so that a temporary + batch file _is_ created when needed for $(shell). + Fixes Savannah bug #16362. + +2010-08-07 Juan Manuel Guerrero + + * configh.dos.template (HAVE_STRNCASECMP): Define. + +2010-07-28 Paul Smith + + Version 3.82 released. + + * configure.in: Change release version. + * NEWS: Change the date. + + * read.c (parse_file_seq): Remove GLOB_NOSORT for + backward-compatibility. We'll add it back in next release. + * NEWS: Note it. + +2010-07-24 Eli Zaretskii + + * job.c (pid2str) [WINDOWS32]: Fix CPP conditionals for using %Id + format. + +2010-07-18 Paul Smith + + * configure.in: Switch bsd_signal to AC_CHECK_DECLS() to make sure + we have a declaration. Fixes Savannah bug #25713 (maybe?) + * doc/make.texi (Complex Makefile): Cleanup variable assignments. + (One Shell): New subsection for the .ONESHELL special target. + + Patches by Ozkan Sezer : + + * misc.c (strncasecmp): Local implementation for systems without. + * config.h.W32.template (HAVE_STRNICMP): Define on Windows. + * configure.in: Check for strncasecmp/strncmpi/strnicmp. + * job.c [WINDOWS32]: Don't define dup2 on Windows. + (pid2str): Use "%Id" even with MSVC + (exec_command): Cast to pid_t when calling pid2str(). + * w32/subproc/sub_proc.c [WINDOWS32]: Include config.h first. + Use stddef.h on MSVC to get intptr_t. + * w32/subproc/misc.c [WINDOWS32]: Include config.h first. + * w32/compat/dirent.c [WINDOWS32]: Include config.h first. + (readdir): Cast -1 to correct type for d_ino. + * w32/pathstuff.c [WINDOWS32]: Ensure make.h is included first. + * make.h [WINDOWS32]: Don't prototype alloca() on Windows. + Add configuration for strncasecmp(). + * main.c (ADD_SIG) [WINDOWS32]: Avoid warnings in MSVC. + * config.h.W32.template [WINDOWS32]: Don't warn on unsafe + functions or variables. + * NMakefile.template [WINDOWS32]: Remove /MACHINE:I386. + * main.c (clean_jobserver): Cast due to MSVC brokenness. + (decode_switches): Ditto. + * vpath.c (construct_vpath_list): Ditto. + * rule.c (freerule): Ditto. + * ar.c (ar_glob): Ditto. + +2010-07-16 Boris Kolpackov + + * misc.c (concat): Fix buffer overrun. + +2010-07-12 Paul Smith + + Update copyrights to add 2010. + + * build_w32.bat: Support for MSVC Windows x86_64 builds. + * job.c: Don't define execve() on MSVC/64bit. + Patch by Viktor Szakats. Fixes Savannah bug #27590. + +2010-07-12 Eli Zaretskii + + * make.h (alloca) [!__GNUC__]: Don't define prototype. + (int w32_kill): Use pid_t for process ID argument. + Fixes Savannah bug #27809. + +2010-07-12 Paul Smith + + Integrated new .ONESHELL feature. + Patch by David Boyce . Modified by me. + + * NEWS: Add a note about the new feature. + * job.c (is_bourne_compatible_shell): Determine whether we're + using a standard POSIX shell or not. + (start_job_command): Accept '-ec' as POSIX shell flags. + (construct_command_argv_internal): If one_shell is set and we are + using a POSIX shell, remove "interior" prefix characters such as + "@", "+", "-". Also treat "\n" as a special character when + choosing the slow path, if ONESHELL is set. + * job.h (is_bourne_compatible_argv): Define the new function. + + * make.h (one_shell): New global variable to remember setting. + * main.c: Declare it. + * read.c (record_files): Set it. + * commands.c (chop_commands): If one_shell is set, don't chop + commands into multiple lines; just keep one line. + +2010-07-09 Eli Zaretskii + + * w32/subproc/sub_proc.c: Include stdint.h. + (sub_process_t): Use intptr_t for file handles and pid_t for + process ID. + (process_pipes, process_init_fd, process_begin): Use intptr_t for + file handles and pid_t for process ID. Fixes Savannah bug #27809. + Patch by Ozkan Sezer + + * function.c (abspath): Support absolute file names in UNC format. + Fixes Savannah bug #30312. + + * job.c (pid2str) [WINDOWS32]: Don't use %Id with GCC < 4.x. + (exec_command) [WINDOWS32]: Use pid2str instead of non-portable + %Id. + + * main.c (handle_runtime_exceptions): Use %p to print addresses, + to DTRT on both 32-bit and 64-bit hosts. Savannah bug #27809. + + * job.c (w32_kill, start_job_command, create_batch_file): Use + pid_t for process IDs and intptr_t for the 1st arg of + _open_osfhandle. + * function.c (windows32_openpipe): Use pid_t for process IDs and + intptr_t for the 1st arg of _open_osfhandle. + (func_shell): Use pid_t for process IDs. + * main.c (main) [WINDOWS32]: Pacify the compiler. + * config.h.W32.template (pid_t): Add a definition for 64-bit + Windows builds that don't use GCC. Fixes Savannah bug #27809. + Patch by Ozkan Sezer + +2010-07-07 Paul Smith + + * configure.in: Bump to a new prerelease version 3.81.91. + +2010-07-06 Paul Smith + + * main.c (main): Set a default value of "-c" for .SHELLFLAGS. + * NEWS: Mention the new behavior of .POSIX and the new .SHELLFLAGS + variable. + * job.c (construct_command_argv): Retrieve the .SHELLFLAGS value + and pass it to construct_command_argv_internal(). + (construct_command_argv_internal): If .SHELLFLAGS is non-standard + use the slow path. Use that value instead of hard-coded "-c". + +2010-07-05 Paul Smith + + * implicit.c (pattern_search): lastslash can be const. + * dir.c (downcase): Remove unused variable. + * hash.c (hash_init): Cast sizeof for error message. + * arscan.c (ar_scan): Cast to char* for WINDOWS32. + (ar_member_touch): Ditto. + * ar.c (glob_pattern_p): Avoid symbol collision: open -> opened + * signame.c (strsignal): Ditto: signal -> sig + * job.c (create_batch_file): Ditto: error -> error_string + (pid2str): Portably convert a pid_t into a string + (reap_children): Use it. + (start_waiting_job): Use it. + Savannah bug #27809. Patch by Ozkan Sezer + +2010-07-03 Paul Smith + + * read.c (parse_file_seq): All archive groups must end with ')' as + the LAST character in a word. If there is no word ending in ')' + then it's not an archive group. Fixes Savannah bug #28525. + +2010-07-01 Paul Smith + + * main.c (main): Append optional features using separate calls. + Not as efficient but not all compilers allow conditionals inside + macro calls. Fixes Savannah bug #29244. + +2010-01-10 Paul Smith + + * make.h (patheq): Rename strieq() to patheq() for clarity. + * dir.c (dir_contents_file_exists_p): Use it. + + * dir.c (file_impossible): Convert xmalloc/memset to xcalloc. + * file.c (enter_file): Ditto. + * job.c (new_job): Ditto. + +2009-12-11 Eli Zaretskii + + * job.c (construct_command_argv_internal) + [WINDOWS32]: Add "echo." and a few more commands that are built + into cmd.exe. Fixes Savannah bug #28126. + + * file.c (lookup_file) [HAVE_DOS_PATHS]: Treat '\\' like we do + with '/'. + +2009-11-15 Paul Smith + + Patches for VMS provided by Hartmut Becker + + * vmsjobs.c (ctrlYPressed) [VMS]: Deal with CTRL-Y. + (vmsHandleChildTerm) [VMS]: Ditto. + (astYHandler) [VMS]: Ditto. + (tryToSetupYAst) [VMS]: Ditto. + (child_execute_job) [VMS]: Ditto. + + * vmsify.c (trnlog) [VMS]: Fix const errors. + (vmsify) [VMS]: Ditto. + + * readme.vms [VMS]: Update with notes for 3.82. + + * job.h (comname) [VMS]: Remember the temporary command filename + + * dir.c (vmsify) [VMS]: Fix const errors. + (vms_hash) [VMS]: Ditto. + (vmsstat_dir) [VMS]: Ditto. + (find_directory) [VMS]: Fix case-insensitive option for VMS + (dir_contents_file_exists_p) [VMS]: Ditto. + (file_impossible) [VMS]: Ditto. + + * config.h-vms.template (HAVE_FDOPEN) [VMS]: Have it. + (HAVE_STRCASECMP) [VMS]: Ditto. + + * arscan.c (VMS_get_member_info) [VMS]: Fix timezone computation. + (ar_scan) [VMS]: Fix const error. + +2009-11-12 Boris Kolpackov + + * vpath.c (vpath_search, selective_vpath_search): Add index arguments + which allows the caller to get the index of the matching directory. + + * make.h (vpath_search): Update prototype. + + * remake.c (library_search): Implement linker-compatible library + search. Use the new VPATH_SEARCH index functionality to keep track + of the directory index for each match. Select the match with the + lowest directory index. + + * implicit.c (pattern_search): Pass NULL for the index arguments in + the VPATH_SEARCH call. + + * doc/make.texi (Directory Search for Link Libraries): Describe the + new search behavior. + + * NEWS: Add a note about the new behavior. + +2009-10-25 Paul Smith + + * AUTHORS, et.al.: Update copyright years. + + * implicit.c (stemlen_compare): Fix qsort() compare bug that + caused implicit rules with equal stem lengths to be sorted + indeterminately. + +2009-10-24 Paul Smith + + * main.c (usage): Add --eval to the usage string. + (switches): Add the --eval switch. + (main): If --eval is given, add them to the simply-expanded variable + -*-eval-flags-*- (necessary to allow recursion to work properly). + (define_makeflags): Add -*-eval-flags-*- to MAKEFLAGS. + + * NEWS: Describe the new --eval command line argument. + * doc/make.texi (Options Summary): Document --eval. + + * dep.h: eval_buffer() returns void. + * read.c (eval_buffer): Ditto. + (eval): Ditto. + + * variable.h (define_variable_cname): New macro for constant + variable names. + * default.c (set_default_suffixes): Use it. + * main.c (main): Ditto. + (handle_non_switch_argument): Ditto. + (define_makeflags): Ditto. + * read.c (read_all_makefiles): Ditto. + * variable.c (define_automatic_variables): Ditto. + + * commands.c (dep_hash_cmp): Avoid casts. + (dep_hash_1): Ditto. + (dep_hash_2): Ditto. + +2009-10-22 Boris Kolpackov + + * read.c (read_all_makefiles): Mark the default makefile dependency + dontcare. + +2009-10-07 Boris Kolpackov + + * read.c (do_undefine): Free the expanded variable name. + + * commands.c (dep_hash_cmp, set_file_variables): Move the order-only + to normal upgrade logic from dep_hash_cmp to set_file_variables. + +2009-10-06 Boris Kolpackov + + * dep.h (uniquize_deps): Remove. + + * read.c (uniquize_deps): Merge into set_file_variables in + commands.c. + (dep_hash_1, dep_hash_2, dep_hash_cmp): Move to commands.c. + + * commands.c (set_file_variables): Avoid modifying the dep + chain to achieve uniqueness. Fixes savannah bug 25780. + + * implicit.c (pattern_search): Instead of re-setting all automatic + variables for each rule we try, just update $*. + +2009-10-06 Boris Kolpackov + + * variable.h (undefine_variable_in_set): New function declaration. + (undefine_variable_global): New macro. + + * variable.c (undefine_variable_in_set): New function implementation. + + * read.c (vmodifiers): Add undefine_v modifier. + (parse_var_assignment): Parse undefine. + (do_undefine): Handle the undefine directive. + (eval): Call do_undefine if undefine_v is set. + + * main.c (.FEATURES): Add a keyword to indicate the new feature. + + * doc/make.texi (Undefine Directive): Describe the new directive. + + * NEWS: Add a note about the new directive. + +2009-10-05 Boris Kolpackov + + * implicit.c (pattern_search): Initialize file variables only + if we need to parse a rule that requires the second expansion. + +2009-10-03 Paul Smith + + * make.h: Include even on systems where __GNUC__ is + defined. Not sure why it was done the other way. + Requested by David Boyce . + +2009-09-30 Boris Kolpackov + + * dep.h (dep): Add the DONTCARE bitfield. + + * filedef.h (file):Add the NO_DIAG bitfield. + + * read.c (eval_makefile): Set the DONTCARE flag in struct dep, + not struct file (a file can be a dependency of many targets, + some don't care, some do). + + * remake.c (update_goal_chain): Propagate DONTCARE from struct + dep to struct file before updating the goal and restore it + afterwards. + (update_file): Don't prune the dependency graph if this target + has failed but the diagnostics hasn't been issued. + (complain): Scan the file's dependency graph to find the file + that caused the failure. + (update_file_1): Use NO_DIAG instead of DONTCARE to decide + whether to print diagnostics. + + Fixes Savannah bugs #15110, #25493, #12686, and #17740. + +2009-09-28 Paul Smith + + * doc/make.texi (Pattern Intro): Move the match algorithm + discussion into the "Pattern Match" node. + (Pattern Match): Expand on the pattern rule matching algorithm. + +2009-09-28 Andreas Buening + + * job.c (construct_command_argv_internal) [OS2]: Don't eat too + much of the command line on a single pass. + +2009-09-28 Boris Kolpackov + + * varible.c (create_pattern_var): Insert variables into the + PATTERN_VARS list in the shortest patterns first order. + + * implicit.c (tryrule): Add STEMLEN and ORDER members. These are + used to sort the rules. + (stemlen_compare): Compare two tryrule elements. + (pattern_search): Sort the rules so that they are in the shortest + stem first order. + + * main.c (.FEATURES): Add a keyword to indicate the new behavior. + + * doc/make.texi (Pattern-specific Variable Values): Describe the + new pattern-specific variables application order. + (Introduction to Pattern Rules): Describe the new pattern rules + search order. + + * NEWS: Add a note about the new behavior. + +2009-09-27 Paul Smith + + * doc/make.texi (Double-Colon): Mention that pattern rules with + double-colons have a different meaning. Savannah bug #27497. + +2009-09-27 Juan Manuel Guerrero + + * configh.dos.template: Remove unconditional definition of + SYS_SIGLIST_DECLARED. + Include because ports of GCC 4.3.0 and later no + longer include it, so macros like __DJGPP_MINOR__ are no longer + defined automatically. + + * Makefile.DOS.template (INCLUDES): Use $(prefix) and the + corresponding variables to define LIBDIR, INCLUDEDIR and LOCALEDIR + instead of using the hardcoded ones. + (SUBDIRS): doc subdir added. + (INFO_DEPS, DVIS): Values changed to 'make.info' and 'make.dvi'. + (TEXI2HTML, TEXI2HTML_FLAGS): Removed. Use makeinfo --html to + create html formated docs. texi2html may not be ported to DOS. + (make.info, make.dvi, make.ps, make.html): Make targets depend on + 'make.texi'. + (.texi.info, .texi, .texi.dvi): Now invoked recursively. Change + -I switch to look in ./ instead of ./doc. + (html): Target depend on html-recursive instead of make_1.html. + (make_1.html): Removed. + (mostlyclean-aminfo): Use $(srcdir)/doc instead of ./ as prefix. + (all-recursive): Allow for more than one subdir in the build + process. + (mostlyclean-recursive, clean-recursive, distclean-recursive) + (maintainer-clean-recursive, check-recursive): Enter in doc/ too. + (tags-recursive): Allow for more than one subdir in the build + process. + (info-recursive, dvi-recursive, ps-recursive, html-recursive): New + targets. Enter into doc/ to produce the targets. + (all-am): $(INFO_DEPS) replaced by info. + +2009-09-26 Paul Smith + + * read.c (record_files): Use free_ns() to free struct nameseq. + (eval): Ditto. + + * rule.c (freerule): Use free_dep_chain(). + + * read.c (record_files): Free FILENAMES chain for implicit rules. + (eval): Static pattern targets go into the string cache. + + * function.c (string_glob): Free NAME in the nameseq chain. + +2009-09-25 Boris Kolpackov + + * implicit.c (pattern_search): Terminate early if we haven't + found any rules to try (performance improvement). + +2009-09-25 Boris Kolpackov + + * implicit.c (pattern_search): Merge three parallel arrays, + TRYRULES, MATCHES, and CHECKED_LASTSLASH, into one array + of struct TRYRULE. In the old version the latter two arrays + had insufficient length. + +2009-09-24 Paul Smith + + * implicit.c (pattern_search): Add back support for order-only + prerequisites for secondary expansion implicit rules, that were + accidentally dropped. If we find a "|", enable order-only mode + and set IGNORE_MTIME on all deps that are seen afterward. + (pattern_search): Fix memory leaks: for intermediate files where + we've already set the file variable and pattern variable sets, be + sure to either save or free them as appropriate. + +2009-09-23 Paul Smith + + Rework the way secondary expansion is stored, for efficiency. + This changes secondary expansion so that ONLY WHEN we know we have + a possibility of needing secondary expansion, do we defer the + secondary expansion. This means more parsing the deps but we use + a lot less memory (due to the strcache). Also, this fixes + Savannah bug #18622. + + * read.c (eval): Don't parse the dep string here anymore. + (record_files): Take the dep argument as an unparsed string. If + secondary expansion is enabled AND the prereq string has a '$' in + it, then set NEED_2ND_EXPANSION and keep the entire string. + Otherwise, parse the dep string here to construct the dep list + with the names in the strcache. + + * misc.c (copy_dep_chain): For NEED_2ND_EXPANSION, we need to + duplicate the name string (others are in the strcache). + + * implicit.c: Remove struct idep and free_idep_chain(): unused. + (struct patdeps): New structure to store prereq information. + (pattern_search): Use the NEED_2ND_EXPANSION flag to determine + which prerequisites need expansion, and expand only those. + + * file.c (split_prereqs): Break parse_prereqs() into two parts: this + and enter_prereqs(). split_prereqs() takes a fully-expanded string + and splits it into a DEP list, handling order-only prereqs. + (enter_prereqs): This function enters a list of DEPs into the file + database. If there's a stem defined, expand any pattern chars. + (expand_deps): Only try to expand DEPs which have NEED_2ND_EXPANSION + set. Use the above functions. + (snap_deps): Only perform second expansion on prereqs that need it, + as defined by the NEED_2ND_EXPANSION flag. + (print_prereqs): New function to print the prereqs + (print_file): Call print_prereqs() rather than print inline. + + * hash.h (STRING_COMPARE): Take advantage of strcache() by + comparing pointers. + (STRING_N_COMPARE): Ditto. + (ISTRING_COMPARE): Ditto. + + * dep.h (PARSE_FILE_SEQ): New macro to reduce casts. + (parse_file_seq): Return void* + * read.c (parse_file_seq): Return void*. + (eval): Invoke macroized version of parse_file_seq() + * default.c (set_default_suffixes): Ditto. + * file.c (split_prereqs): Ditto. + * function.c (string_glob): Ditto. + * main.c (main): Ditto. + * rule.c (install_pattern_rule): Ditto. + + * filedef.h: Add split_prereqs(), enter_prereqs(), etc. + +2009-09-16 Paul Smith + + * misc.c (alloc_dep, free_dep): Now that we have xcalloc(), + convert to macros. + * dep.h: Create alloc_dep() / free_dep() macros. + + * implicit.c (pattern_search): Take advantage of the new + parse_file_seq() to add the directory prefix to each prereq. + + * dep.h: Remove multi_glob() and enhance parse_file_seq() to do it + all. Avoid reversing chains. Support adding prefixes. + * read.c (parse_file_seq): Rewrite to support globbing. Allow for + cached/non-cached results. + (eval): Remove multi_glob() & invoke new parse_file_seq(). + * rule.c (install_pattern_rule): Ditto. + * main.c (main): Ditto. + * implicit.c (pattern_search): Ditto. + * function.c (string_glob): Ditto. + * file.c (parse_prereqs): Ditto. + * default.c (set_default_suffixes): Ditto. + + * variable.c (parse_variable_definition): Don't run off the end of + the string if it ends in whitespace (found with valgrind). + + * commands.c (set_file_variables): Keep space for all targets in + $? if -B is given (found with valgrind). + +2009-09-15 Paul Smith + + * misc.c (concat): Make concat() variadic so it takes >3 arguments. + (xcalloc): Add new function. + * make.h: New declarations. + + * ar.c (ar_glob_match): New calling method for concat(). + * main.c (main): Ditto. + (decode_env_switches): Ditto. + * read.c (eval_makefile): Ditto. + (tilde_expand): Ditto. + (parse_file_seq): Ditto. + * variable.c (target_environment): Ditto. + (sync_Path_environment): Ditto. + + * ar.c (ar_glob_match): Use xcalloc(). + * dir.c (file_impossible): Ditto. + * file.c (enter_file): Ditto. + * job.c (new_job): Ditto. + * read.c (parse_file_seq): Ditto. + * vmsfunctions.c (opendir): Ditto. + +2009-09-14 Rafi Einstein (tiny patch) + + * w32/subproc/sub_proc.c (process_begin): Check *ep non-NULL + inside the loop that looks up environment for PATH. + +2009-08-31 Eli Zaretskii + + * function.c (windows32_openpipe): Update envp after calling + sync_Path_environment. + +2009-08-02 Paul Smith + + * remake.c (notice_finished_file): Ensure file->cmds is not null + before looping through them. Fixes Savannah bug #21824. + + * doc/make.texi (Wildcard Examples): Clarify when objects is + wildcard-expanded. Fixes Savannah bug #24509. Patch by Martin Dorey. + (Include): Clarify the behavior of -include. + Fixes Savannah bug #18963. + +2009-08-01 Paul Smith + + * doc/make.texi (Catalogue of Rules): Clarify where -c, -F, + etc. come on the command line. Fixes Savannah bug #27093. + + * expand.c (expand_argument): If the argument is large enough use + xmalloc() instead of alloca(). Fixes Savannah bug #27143. + + * variable.c (do_variable_definition): Avoid using alloca() to + hold values, which can be large. Fixes Savannah bug #23960. + + * job.c (new_job): Use memmove() instead of strcpy() since both + pointers are in the same memory block. Fixes Savannah bug #27148. + Patch by Petr Machata. + +2009-07-29 Ralf Wildenhues + + * job.c (construct_command_argv_internal): Add "ulimit" and + "unset" to the sh_cmds for Unixy shells. + +2009-07-29 Ralf Wildenhues + + * configure.in: Move side-effects outside AC_CACHE_VAL arguments + that set make_cv_sys_gnu_glob, so they are also correctly set + when the cache has been populated before. + +2009-07-04 Eli Zaretskii + + * function.c (func_realpath) [!HAVE_REALPATH]: Require the file to + exist, as realpath(3) does where it's supported. + +2006-07-04 Eli Zaretskii + + * function.c (IS_ABSOLUTE, ROOT_LEN): New macros. + (abspath): Support systems that define HAVE_DOS_PATHS (have + drive letters in their file names). Use IS_PATHSEP instead of a + literal '/' comparison. Fixes Savannah bug #26886. + +2009-06-14 Paul Smith + + * remake.c (update_file_1): Remember the original file we marked + as updating, so we can clear that flag again. If we find a target + via vpath, FILE might change. + (check_dep): Ditto. Fixes Savannah bug #13529. + Patch by Reid Madsen . + +2009-06-13 Paul Smith + + * doc/make.texi (MAKEFILES Variable): Be explicit that files + included by MAKEFILES cannot give default goals. + * read.c (eval): If set_default is not set, pass the no-default-goal + value when we read included makefiles. Fixes Savannah bug #13401. + + * ar.c (ar_name): Ensure that targets with empty parens aren't + considered archive member references: archive members must have a + non-empty "member" string. Fixes Savannah bug #18435. + + * function.c (string_glob): Rely on multi_glob() to determine + whether files exist or not. Remove call to file_exists_p() which + is not always correct. Fixes Savannah bug #21231. + * read.c (multi_glob): Add a new argument EXISTS_ONLY; if true + then only files that really exist will be returned. + * dep.h: Add new argument to multi_glob(). + * rule.c (install_pattern_rule): Ditto. + * read.c (eval): Ditto. + * main.c (main): Ditto. + * implicit.c (pattern_search): Ditto. + * file.c (parse_prereqs): Ditto. + * default.c (set_default_suffixes): Ditto. + +2009-06-09 Paul Smith + + * commands.c (set_file_variables): If always_make_flag is set, + always add the prereq to $?. Fixes Savannah bug #17825. + + * remake.c (update_file_1): When rebuilding deps of FILE, also try + to rebuild the deps of all the also_make targets for that file. + Fixes Savannah bug #19108. + + * implicit.c (pattern_search): Undo test for is_target, added by + BorisK on 21 Sep 2004. This goes against step 5c in the "Implicit + Rule Search Algorithm". Fixes Savannah bug #17752. + + * main.c (clean_jobserver): Clear the jobserver_fds options and + set job_slots to the default when we clean up. + (define_makeflags): Return the new MAKEFLAGS value. + (main): Reset MAKEFLAGS in the environment when we re-exec. + Fixes Savannah bug #18124. + +2009-06-08 Paul Smith + + * read.c (eval): Collapse continuations post-semicolon on target- + specific variables. Fixes Savannah bug #17521. + +2009-06-07 Paul Smith + + * job.c (reap_children): For older systems without waitpid() (are + there any of these left?) run wait(2) inside EINTRLOOP to handle + EINTR errors. Fixes Savannah bug #16401. + + * (various): Debug message cleanup. Fixes Savannah bug #16469. + + * main.c: Fix bsd_signal() typedef. Fixes Savannah bug #16473. + + * file.c (snap_deps): Set SNAPPED_DEPS at the start of snapping, + not the end, to catch second expansion $(eval ...) defining new + target/prereq relationships during snap_deps. + Fixes Savannah bug #24622. + + * read.c (record_files): The second-expansion "f->updating" hack + was not completely correct: if assumed that the target with + commands always had prerequisites; if one didn't then the ordering + was messed up. Fixed for now to use f->updating to decide whether + to preserve the last element in the deps list... but this whole + area of constructing and reversing the deps list is too confusing + and needs to be reworked. Fixes Savannah bug #21198. + +2009-06-06 Paul Smith + + * hash.c (hash_insert): Remove useless test for NULL. + Fixes Savannah bug #21823. + + * make.h: Move SET_STACK_SIZE determination to make.h. + * main.c (main): New global variable, STACK_LIMIT, holds the + original stack limit when make was started. + * job.c (start_job_command): Reset the stack limit, if we changed it. + Fixes Savannah bug #22010. + + * remake.c (check_dep): Only set the target's state to not-started + if it's not already running. Found this while testing -j10 builds + of glibc: various targets were being rebuilt multiple times. + Fix from Knut St. Osmundsen; fixes a problem reported in Savannah + bug #15919. + + * read.c (multi_glob): Don't pass GLOB_NOCHECK to glob(3); instead + handle the GLOB_NOMATCH error. This is to work around Sourceware.org + Bugzilla bug 10246. + +2009-06-04 Paul Smith + + * read.c (eval): Skip initial whitespace (ffeed, vtab, etc.) + + * maintMakefile: Modify access of config and gnulib Savannah + modules to use GIT instead of CVS. + + * main.c (main): Initialize the LENGTH field in SHELL_VAR. + Fixes Savannah bug #24655. + + * read.c (eval_buffer): Don't dereference reading_file if it's NULL; + this can happen during some invocations of $(eval ...) for example. + Fixes Savannah bug #24588. Patch by Lars Jessen + +2009-06-02 Paul Smith + + * configure.in: Check for fileno() + * read.c (eval_makefile): If fileno() is available, set CLOSE_ON_EXEC + for the makefile file so invocations of $(shell ...) don't inherit it. + Fixes Savannah bug #24277. + +2009-06-01 Paul Smith + + * main.c (main): The previous fix for .DEFAULT_GOAL had issues; + expansion was handled incorrectly. Rework the default goal + handling to save the variable only. Remove default_goal_file and + default_goal_name. + * read.c (eval): Check default_goal_var, not default_goal_name. + * read.c (record_target_var): Don't check default_goal_file here. + +2009-05-31 Paul Smith + + * main.c (main): Expand the .DEFAULT_GOAL variable before using + it, and if the multi_glob() returns nothing (say it expanded to + nothing but spaces) then don't crash. Fixes Savannah bug #25697. + + * doc/make.texi (Quick Reference): Add $(if ..), $(or ..), and + $(and ..) to the reference. Fixes Savannah bug #25694. + + * make.1: Be clear that some recipes will be executed even with -n. + * doc/make.texi: Ditto. Fixes Savannah bug #25460. + + * doc/make.texi (Override Directive): Make more clear how + overrides and appends interact. + Elucidates part of Savannah bug #26207. + + * read.c (record_target_var): Don't reset the origin on + target-specific variables; try_variable_definition() will handle + this correctly. Fixes Savannah bug #26207. + + * maintMakefile (do-po-update): Copy PO files into $(top_srcdir). + Fixes Savannah bug #25712. + + * implicit.c (pattern_search): Keep a pointer to the beginning of + the filename and save that instead of the constructed pointer. + Fixes Savannah bug #26593. + Patch by Mark Seaborn + +2009-05-30 Paul Smith + + * doc/make.texi (Multi-Line): Add a description of the new abilities + of define/endef. Rename "Sequences" to "Multi-Line" and fix some + "command sequence" vs. "recipe" syntax. + * read.c (do_define): Modify to allow assignment tokens (=, :=, etc.) + after a define, to create variables with those flavors. + +2009-05-25 Paul Smith + + Reworked the parser for variable assignments to allow multiple + modifiers, and in any order. Also allows variable and + prerequisites to be modifier names ('export', 'private', etc.) + + * NEWS: Add notes about user-visible changes. + + * read.c (struct vmodifiers): Remember what modifiers were seen. + (parse_var_assignment): New function to parse variable assignments. + (eval): Call the new function. Handle variable assignments earlier. + + * variable.c (parse_variable_definition): Only parse; don't create var. + (assign_variable_definition): Call parse, then create the var. + +2009-05-24 Paul Smith + + * doc/make.texi: Fix the ISBN for the GNU make manual. Incorrect + value noticed by Hans Stol . + +2009-03-14 Eli Zaretskii + + * w32/pathstuff.c (convert_Path_to_windows32): Fix last change. + Fixes Savannah bug #25412. + + * w32/subproc/sub_proc.c : Update Copyright years. Add + prototype for xmalloc. + (find_file): Accept 3 arguments PATH_VAR, FULL_FNAME, and FULL_LEN + instead of an LPOFSTRUCT pointer. Use xmalloc instead of malloc. + Loop over an array of extensions, instead of duplicating the same + code inline. Use SearchPath followed by CreateFile, instead of + the obsolete OpenFile. Fixes Savannah bug #17277. + (process_begin): Find $(PATH) in `envp', and pass a pointer to it + to `find_file'. Fixes Savannah bug #25662. + +2009-03-07 Eli Zaretskii + + * function.c (func_shell): Don't close pipedes[1] if it is -1. + Fixes Savannah bug #20495. + +2009-02-28 Ralf Wildenhues + + * doc/make.texi (Instead of Execution): Document interaction of + -t with phony targets. + +2009-02-23 Ramon Garcia + + Introduce a new keyword "private" which applies to target-specific + variables and prevents their values from being inherited. + + * variable.h (struct variable): Add private_var flag to each variable. + Add a flag to specify which list entry switches to the parent target. + * variable.c (define_variable_in_set): Initialize private_var flag. + (lookup_variable): Skip private variables in parent contexts. + (initialize_file_variables): Set next_is_parent appropriately. + (print_variable): Show the private_var flag. + * read.c (eval): Recognize the private keyword. + (record_target_var): Set private_var. + * doc/make.texi (Suppressing Inheritance): Add documentation. + +2008-10-26 Paul Smith + + * configure.in: Check for strndup(). + * misc.c (xstrndup): Rename savestring to xstrndup. Use strndup + if it's available. + * make.h: Rename savestring to xstrndup. + * commands.c (chop_commands): Ditto. + * function.c (func_foreach): Ditto. + * read.c (eval, record_files): Ditto. + * variable.c (define_variable_in_set): Ditto. + +2008-09-30 Eli Zaretskii + + * build_w32.bat (GCCBuild): Use "-gdwarf-2 -g3" instead of + "-gstabs+ -ggdb3". + + * w32/subproc/build.bat (GCCBuild): Likewise. + +2008-09-30 David Russo (tiny change) + + * job.c (construct_command_argv_internal): Avoid extra backslash + in batch-mode Unixy shells. Under DB_JOBS, display the contents + of the batch file. + +2008-05-31 Eli Zaretskii + + * README.W32.template: Remove obsolete text about non-support for + -jN without Unixy shell. Remove obsolete text about not supplying + Visual Studio project files (we do supply them). Modify text to + prefer GCC builds to MSC builds. + +2008-04-02 Ralf Wildenhues + + * doc/make.texi (Empty Targets): Fix typo. + +2008-03-27 Paul Smith + + Fix Savannah bug #22379: + * ar.c (ar_glob_match): Zero the allocated structure. + * read.c (parse_file_seq): Ditto. + +2008-03-08 Brian Dessent + + * maintMakefile: Update Translation Project location. + +2008-01-26 Eli Zaretskii + + * variable.c (target_environment): Don't use shell_var if its + `value' field is NULL. + +2007-12-22 Eli Zaretskii + + Suggested by Juan Manuel Guerrero : + + * Makefile.DOS.template (info_TEXINFOS): Remove unused variable. + (TEXINFOS): Value changed to `doc/make.texi'. + (.SUFFIXES): Use .texi instead of .texinfo. + (make.info, make.dvi): Depend on doc/make.texi. + (.texi.info): New target, instead of ".texinfo.info". Change -I + switch to $(MAKEINFO) to look in doc/. Use --no-split. + (.texi): New target, instead of ".texinfo". Change -I switch to + $(MAKEINFO) to look in doc/. Use --no-split. + (.texi.dvi): New target, instead of ".texinfo.dvi". Change -I + switch to $(MAKEINFO) to look in doc/. + (install-info-am, uninstall-info): Don't look for "*.i[0-9]" and + "*.i[0-9][0-9]" (due to --no-split above). + (noinst_TEXINFOS, TEXI2HTML, TEXI2HTML_FLAGS): New variables. + (html, make_1.html): New targets. + (.PHONY): Add "html". + (.SUFFIXES): Add .html. + +2007-12-22 Juan Manuel Guerrero (tiny change) + + * configh.dos.template [__DJGPP__]: Replace HAVE_SYS_SIGLIST with + HAVE_DECL_SYS_SIGLIST. + + * job.c (child_execute_job): Remove __MSDOS__ because MSDOS/DJGPP + build does not use child_execute_job. + + * variable.c (define_automatic_variables) [__MSDOS__]: Always + export the SHELL environment variable to the child. + +2007-12-22 Eli Zaretskii + + * config.h.W32: Include sys/types.h. + [!_PID_T_] (pid_t): Define only if not already defined by sys/types.h. + + * vpath.c (construct_vpath_list) [HAVE_DOS_PATHS]: Support VPATH + values that use `:' in drive letters, when PATH_SEPARATOR_CHAR is + also `:'. + +2007-11-04 Paul Smith + + * doc/make.texi: Convert references to "commands", "command + lines", and "command script" to "recipe". + * NEWS: Ditto. + * commands.c, file.c, job.c, remake.c, read.c, variable.c, main.c: + Ditto. + +2007-10-27 Bruno Haible + + * remake.c (f_mtime): Print time difference values between 100 and + ULONG_MAX in fixed-point notation rather than in exponention notation. + +2007-10-12 Eli Zaretskii + + * variable.c (do_variable_definition): Allow $(SHELL) to expand to + a more complex value than a simple shell: if it's not a default + shell now then expand it and see if is a default shell then. + +2007-10-10 Eli Zaretskii + + * dir.c (find_directory) [WINDOWS32]: Remove trailing slashes from + pathnames, with const strings. + * build_w32.bat [WINDOWS32]: If no config.h.W32 exists, create one + from the template (used for building from CVS, not a dist). + +2007-10-10 Paul Smith + + * make.h: Add a prototype for w32_kill() (change suggested by + Yongwei Wu ). + +2007-09-21 Eli Zaretskii + + * w32/pathstuff.c (convert_Path_to_windows32): Handle quoted + directories in Path. + +2007-09-12 Paul Smith + + * doc/make.texi: Applied wording cleanups from Savannah patch #6195. + Provided by Diego Biurrun + (Complex Makefile): Remove .PHONY setting for tar: patch #6196. + Provided by Diego Biurrun + +2007-09-11 Paul Smith + + * doc/make.texi (Special Variables): Moved this into the "How to + Use Variables" chapter. Added a table entry for .RECIPEPREFIX. + (MAKEFILE_LIST) No longer a section; this was added into the + "Special Variables" section. + (Rule Introduction): Reference .RECIPEPREFIX. + (Simple Makefile): Ditto. + (Rule Syntax): Ditto. + (Command Syntax): Ditto. + (Error Messages): Ditto. + +2007-09-10 Paul Smith + + * commands.c (print_commands): Don't print an extra line in the + command scripts. Prefix the command scripts with cmd_prefix, not \t. + + * read.c (construct_include_path): Add the full string to the cache; we + were chopping the last char. + + * NEWS: Announce the .RECIPEPREFIX special variable. + * variable.c (lookup_special_var): Rename from handle_special_var(). + (lookup_variable): Call the new name. + (set_special_var): New function: handle setting of special variables. + When setting .RECIPEPREFIX, reset the cmd_prefix global variable. + (do_variable_definition): Call it. + * make.h (RECIPEPREFIX_DEFAULT): Define the default command prefix char. + (RECIPEPREFIX_NAME): Define the command prefix special variable name. + * main.c (main): Create the .RECIPEPREFIX special variable. + * read.c (eval): Remove the cmd_prefix characters from the command + scripts here, so they're not stored in the commands array at all, + rather than waiting and stripping them out during command construction. + * job.c (construct_command_argv_internal): Don't skip cmd_prefix here. + +2007-08-15 Paul Smith + + * doc/make.texi (GNU Free Documentation License): The fdl.texi + file has had the section info removed, so add some to make.texi + before we include it. + +2007-08-15 Icarus Sparry + + * remake.c (check_dep): Reset the target state for intermediate + files. They might have been considered before but not updated + then (order-only for example) but they will be this time. + Fixes Savannah bug #'s 3330 and 15919. + +2007-07-21 Eli Zaretskii + + Fix Savannah bug #20549: + * function.c (func_shell): Call construct_command_argv with zero + value of FLAGS. + * job.c (construct_command_argv_internal): New argument FLAGS; all + callers changed. + [WINDOWS32]: If FLAGS has the COMMANDS_RECURSE bit set, ignore + just_print_flag. + * job.h (construct_command_argv_internal): Update prototype. + +2007-07-13 Paul Smith + + * file.c (expand_deps): Use variable_buffer as the start of the + buffer, not the original pointer (in case it was reallocated). + Fix suggested by Rafi Einstein . + Fixes Savannah bug #20452. + +2007-07-04 Paul Smith + + * (ALL FILES): Update to GPLv3. + * (ALL FILES): Update copyright for 2007. + + * main.c (print_version): Move the host type info to the second line. + +2007-06-29 Thiemo Seufer + + * maintMakefile: Update Translation Project location. + +2007-06-13 Paul Smith + + * doc/make.texi (Reading Makefiles): "Expansion of deferred" -> + "Expansion of a deferred" + Fixes Savannah bug #20018. + + * expand.c (variable_expand_for_file): Preserve the value of + reading_file rather than setting it to 0 at the end. + Fixes Savannah bug #20033. + +2007-05-11 Paul Smith + + * job.c (new_job): Add debug info to specify where make found the + command script it is running to build a target. + Fixes Savannah bug #18617. + + * default.c (default_suffixes,default_suffix_rules,default_variables): + Add support for Objective C. Fixes Savannah bug #16389. + Based on a patch provided by Peter O'Gorman . + + * function.c (func_lastword): Initialize p. + + * doc/make.texi (Eval Function, Implicit Variables, Special Targets): + Doc fixes noticed by Bob . Patch from + Dave Korn + +2007-05-08 Paul Smith + + Fix Savannah bug #19656: + + * configure.in: Check for strcasecmp(), strcmpi(), and stricmp(). + + * make.h: Change all case-insensitive string compares to use + strcasecmp() (from POSIX). If we don't have that but do have one + of the others, define strcasecmp to be one of those instead. If + we don't have any, declare a prototype for our own version. + + * misc.c (strcasecmp): Use this if we can't find any native + case-insensitive string comparison function. + * vmsfunctions.c: Remove strcmpi(); we'll use misc.c:strcasecmp(). + * main.c (find_and_set_default_shell): Use strcasecmp() instead of + strcmpi(). + * job.c (_is_unixy_shell, construct_command_argv_internal): Use + strcasecmp() instead of stricmp(). + * hash.h (ISTRING_COMPARE, return_ISTRING_COMPARE): Use strcasecmp() + instead of strcmpi(). + * acinclude.m4: Remove the strcasecmp() check from here. + +2007-03-21 Paul Smith + + * configure.in: Don't turn on case-insensitive file system support + if --disable-... is given. Fixes Savannah bug #19348. + +2007-03-19 Paul Smith + + * ALL: Use the strcache for all file name strings, or other + strings which we will never free. The goal is to save memory by + avoiding duplicate copies of strings. However, at the moment this + doesn't save much memory in most situations: due to secondary + expansion we actually save prerequisite lists twice (once before + the secondary expansion, and then again after it's been parsed + into individual file names in the dep list). We will resolve this + in a future change, by doing the parsing up-front for targets + where secondary expansion is not set. + + Moving things into the strcache also allows us to use const + pointers in many more places. + +2007-01-03 Paul Smith + + * make.h (ENULLLOOP): Reset errno after each failed invocation of + the function, not just the first. Fixes Savannah bug #18680. + +2006-11-18 Paul Smith + + * strcache.c (strcache_add_len): Don't allocate a new buffer + unless the string is not already nil-terminated. Technically this + is a violation of the standard, since we may be passed an array + that is not long enough to test one past. However, in make this + is never true since we only use nil-terminated strings or + sub-strings thereof. + + * read.c (eval, do_define): Use cmd_prefix instead of '\t'. + + * main.c: New global cmd_prefix, defaults to '\t'. + * job.c (construct_command_argv_internal): Use cmd_prefix instead + of '\t'. + + * dir.c: Constified. + (dir_contents_file_exists_p): Check for an error return from + readdir(), just in case. + + * commands.c: Constified. + * default.c: Constified. + * expand.c: Constified. + * function.c: Partial constification. + * variable.c: Partial constification. + * vmsify.c: Constification. Hard to test this but I hope I didn't + screw it up! + * vpath.c: Partial constification. + * w32/pathstuff.c: Partial constification. + +2006-11-16 Eli Zaretskii + + * main.c (main) [HAVE_DOS_PATHS]: Treat DOS style argv[0] with + backslashes and drive letters as absolute. + +2006-10-22 Paul Smith + + * main.c (struct command_switch): Use const and void*. + +2006-10-21 Paul Smith + + * ar.c: Constified. + * arscan.c: Constified. + +2006-09-30 Paul Smith + + * doc/make.texi (MAKEFILE_LIST Variable): Modify reference to + point to lastword since the example was updated. + Fixes Savannah bug #16304. + (Secondary Expansion): Correct example description. + Fixes Savannah bug #16468. + (Makefile Contents): Clarify that comments cannot appear within + variable references or function calls. + Fixes Savannah bug #16577. + (Special Targets): Clarify how .NOTPARALLEL works in recursion. + Fixes Savannah bug #17701. + Reported by Ralf Wildenhues : + (Prerequisite Types): Added an example of using order-only + prerequisites. Fixes Savannah bug #17880. + (Rule Syntax): "lise" -> "list" + (Multiple Rules): ... -> @dots{} + (Splitting Lines): ditto. + + * remake.c (update_file_1): Prereqs that don't exist should be + considered changed, for the purposes of $?. + Fixes Savannah bug #16051. + + * make.1: Remove extraneous "+". + Fixes Savannah bug #16652. + +2006-09-06 Paul D. Smith + + * configure.in: Include sys/types.h when checking for sys/wait.h. + +2006-08-18 Eli Zaretskii + + * configure.in (PATH_SEPARATOR_CHAR): Define to the value of + $PATH_SEPARATOR. + + * make.h (PATH_SEPARATOR_CHAR): Define only if still undefined. + Normally, it is defined in config.h. + + * config/dospaths.m4 : Define to yes on Cygwin as + well. + + * job.c (construct_command_argv_internal) [HAVE_DOS_PATHS]: Define + sh_chars_sh for Windows platforms that emulate Unix. + +2006-05-07 Paul D. Smith + + * README.OS2.template: Updates provided by Andreas Buening + . + +2006-04-30 Paul D. Smith + + * make.h: Include if HAVE_DIRECT_H. + * config.h.W32.template (HAVE_DIRECT_H): Set it if it's available. + +2006-04-26 Paul D. Smith + + * README.cvs: Add a reminder to notify the GNU translation robot. + + * doc/make.texi: Change @direcategory (requested by Karl Berry). + +2006-04-20 Paul D. Smith + + * maintMakefile (po-check): Use Perl instead of grep -E, for systems + that don't have extended grep. + (cvsclean): Use $(PERL) instead of perl. + +2006-04-09 Paul D. Smith + + * maintMakefile: Add some extra warning options (GCC 4.1 only?) + + * expand.c, implicit.c, main.c, read.c: Rename variables so that + inner-scope variables don't mask outer-scope variables. + + * ar.c, arscan.c, commands.c, default.c, dir.c, expand.c, file.c: + * function.c, getloadavg.c, implicit.c, job.c, main.c, misc.c, read.c: + * remake.c, remote-cstms.c, rule.c, strcache.c, variable.c: + * vmsfunctions.c, vmsify.c, vpath.c: Remove all casts of returned + values from memory allocation functions: they return void* and so + don't need to be cast. Also remove (char *) casts of arguments to + xrealloc(). + + * configure.in: Remove checks for memcpy/memmove/strchr. + + * make.h: Remove bcmp/bcopy/bzero/strchr/strrchr macros. + + * ar.c, arscan.c, commands.c, dir.c: Convert all bzero/bcopy/bcmp + calls to memset/memcpy/memmove/memcmp calls. + * expand.c, file.c, function.c, getloadavg.c, implicit.c: Ditto. + * job.c, main.c, misc.c, read.c, remake.c, rule.c: Ditto. + * variable.c, vpath.c: Ditto. + + * make.h (EXIT_FAILURE): Should be 1, not 0. + +2006-04-06 Paul D. Smith + + * configure.in: Removed AM_C_PROTOTYPES. Starting now on we + require an ISO C 1989 standard compiler and runtime library. + + * Makefile.am: Remove the ansi2knr feature. + + * make.h: Remove the PARAMS() macro definition and all uses of it. + + * amiga.h, ar.c, arscan.c: Remove all uses of the PARAMS() macro. + * commands.c, commands.h, config.h-vms.template: Ditto. + * dep.h, dir.c, expand.c, filedef.h, function.c: Ditto. + * implicit.c, job.c, job.h, main.c, read.c, remake.c: Ditto. + * rule.c, rule.h, variable.h, vmsdir.h, vmsjobs.c, vpath.c: Ditto. + + * NEWS: Update. + +2006-04-01 Paul D. Smith + + Version 3.81 released. + + * NEWS: Updated for 3.81. + + * README.cvs: Mention that vpath builds are not supported out of + CVS. Fixes Savannah bug #16236. + Remove update of make.texi from the list of things to do; we use + version.texi now. + +2006-03-26 Paul D. Smith + + * doc/make.texi: Clean up licensing. Use @copying and version.texi + support from automake, as described in the Texinfo manual. + +2006-03-25 Eli Zaretskii + + * implicit.c (pattern_search) [HAVE_DOS_PATHS]: Don't compare b + with lastslash, since the latter points to filename, not to + target. + * job.c (construct_command_argv_internal) [HAVE_DOS_PATHS]: + Declare and define sh_chars_sh[]. + +2006-03-23 Paul D. Smith + + * configure.in: Look for build.sh.in in $srcdir so it will be + built for remote configurations as well. + + * Makefile.am: Make sure to clean up build.sh during distclean. + Fixes Savannah bug #16166. + + * misc.c (log_access): Takes a const char *. + * function.c (fold_newlines): Takes an unsigned int *. + Both fixes for Savannah bug #16170. + +2006-03-22 Boris Kolpackov + + * implicit.c (pattern_search): Call set_file_variables only + if we have prerequisites that need second expansion. Fixes + Savannah bug #16140. + +2006-03-19 Paul D. Smith + + * remake.c (update_file): Add alloca(0) to clean up alloca'd + memory on hosts that don't support it directly. + + * README.cvs: Add information on steps for making a release (to + make sure I don't forget any). + + * main.c (clean_jobserver): Move jobserver cleanup code into a new + function. + (die): Cleanup code was removed from here; call the new function. + (main): If we are re-execing, clean up the jobserver first so we + don't leak file descriptors. + Reported by Craig Fithian + +2006-03-17 Paul D. Smith + + * maintMakefile (do-po-update): Rewrite this rule to clean up and + allow multiple concurrent runs. + Patch from Joseph Myers + +2006-03-17 Boris Kolpackov + + * dep.h (struct dep): Add the stem field. + * misc.c (alloc_dep, free_dep): New functions. + (copy_dep_chain): Copy stem. + (free_dep_chain): Use free_dep. + * read.c (record_files): Store stem in the dependency line. + * file.c (expand_deps): Use stem stored in the dependency line. Use + free_dep_chain instead of free_ns_chain. + * implicit.c (pattern_search): Use alloc_dep and free_dep. + * read.c (read_all_makefiles, eval_makefile, eval): Ditto. + * main.c (main, handle_non_switch_argument): Ditto. + * remake.c (check_dep): Ditto. + * rule.c (convert_suffix_rule, freerule): Ditto. + +2006-03-14 Paul D. Smith + + * expand.c (variable_append): Instead of appending everything then + expanding the result, we expand (or not, if it's simple) each part + as we add it. + (allocated_variable_append): Don't expand the final result. + Fixes Savannah bug #15913. + +2006-03-09 Paul Smith + + * remake.c (update_file_1): Revert the change of 3 Jan 2006 which + listed non-existent files as changed. Turns out there's a bug in + the Linux kernel builds which means that this change causes + everything to rebuild every time. We will re-introduce this fix + in the next release, to give them time to fix their build system. + Fixes Savannah bug #16002. + Introduces Savannah bug #16051. + + * implicit.c (pattern_search) [DOS_PATHS]: Look for DOS paths if + we *don't* find UNIX "/". + Reported by David Ergo + +2006-03-04 Eli Zaretskii + + * variable.c (do_variable_definition) [WINDOWS32]: Call the shell + locator function find_and_set_default_shell if SHELL came from the + command line. + +2006-02-20 Paul D. Smith + + * variable.c (merge_variable_set_lists): It's legal for *setlist0 + to be null; don't core in that case. + +2006-02-19 Paul D. Smith + + * commands.c (set_file_variables): Realloc, not malloc, the static + string values to avoid memory leaks. + + * expand.c (recursively_expand_for_file): Only set reading_file to + an initialized value. + + * implicit.c (pattern_search): We need to make a copy of the stem + if we get it from an intermediate dep, since those get freed. + + * file.c (lookup_file) [VMS]: Don't lowercase special targets that + begin with ".". + (enter_file) [VMS]: Ditto. + Patch provided by Hartmut Becker . + +2006-02-24 Eli Zaretskii + + * job.c (construct_command_argv_internal): Fix last change. + + * w32/subproc/sub_proc.c (process_pipe_io): Make dwStdin, + dwStdout, and dwStderr unsigned int: avoids compiler warnings in + the calls to _beginthreadex. + + * expand.c (recursively_expand_for_file): Initialize `save' to + prevent compiler warnings. + +2006-02-18 Eli Zaretskii + + * job.c (construct_command_argv_internal): Don't create a temporary + script/batch file if we are under -n. Call _setmode to switch the + script file stream to text mode. + +2006-02-17 Paul D. Smith + + * variable.c (merge_variable_set_lists): Don't try to merge the + global_setlist. Not only is this useless, but it can lead to + circularities in the linked list, if global_setlist->next in one + list gets set to point to another list which also ends in + global_setlist. + Fixes Savannah bug #15757. + +2006-02-15 Paul D. Smith + + Fix for Savannah bug #106. + + * expand.c (expanding_var): Keep track of which variable we're + expanding. If no variable is being expanded, it's the same as + reading_file. + * make.h (expanding_var): Declare it. + * expand.c (recursively_expand_for_file): Set expanding_var to the + current variable we're expanding, unless there's no file info in + it (could happen if it comes from the command line or a default + variable). Restore it before we exit. + * expand.c (variable_expand_string): Use the expanding_var file + info instead of the reading_file info. + * function.c (check_numeric): Ditto. + (func_word): Ditto. + (func_wordlist): Ditto. + (func_error): Ditto. + (expand_builtin_function): Ditto. + (handle_function): Ditto. + +2006-02-14 Paul D. Smith + + * read.c (eval): Even if the included filenames expands to the + empty string we still need to free the allocated buffer. + + * implicit.c (pattern_search): If we allocated a variable set for + an impossible file, free it. + * variable.c (free_variable_set): New function. + * variable.h: Declare it. + + * read.c (read_all_makefiles): Makefile names are kept in the + strcache, so there's never any need to alloc/free them. + (eval): Ditto. + + * main.c (main): Add "archives" to the .FEATURES variable if + archive support is enabled. + * doc/make.texi (Special Variables): Document it. + +2006-02-13 Paul D. Smith + + * implicit.c (pattern_search): Add checking for DOS pathnames to + the pattern rule target LASTSLASH manipulation. + Fixes Savannah bug #11183. + +2006-02-11 Paul D. Smith + + * (ALL FILES): Updated copyright and license notices. + +2006-02-10 Paul D. Smith + + A new internal capability: the string cache is a read-only cache + of strings, with a hash table interface for fast lookup. Nothing + in the cache will ever be freed, so there's no need for reference + counting, etc. This is the beginning of a full solution for + Savannah bug #15182, but for now we only store makefile names here. + + * strcache.c: New file. Implement a read-only string cache. + * make.h: Add prototypes for new functions. + * main.c (initialize_global_hash_tables): Initialize the string cache. + (print_data_base): Print string cache stats. + * read.c (eval_makefile): Use the string cache to store makefile + names. Rewrite the string allocation to be sure we free everything. + +2006-02-10 Eli Zaretskii + + * dir.c (dir_contents_file_exists_p): Don't opendir if the + directory time stamp didn't change, except on FAT filesystems. + Suggested by J. David Bryan . + +2006-02-09 Paul D. Smith + + * function.c (func_or): Implement a short-circuiting OR function. + (func_and): Implement a short-circuiting AND function. + (function_table_init): Update the table with the new functions. + * doc/make.texi (Conditional Functions): Changed the "if" section + to one on general conditional functions. Added documentation for + $(and ...) and $(or ...) functions. + * NEWS: Note new $(and ...) and $(or ...) functions. + +2006-02-08 Boris Kolpackov + + * job.h (struct child): Add the dontcare bitfield. + * job.c (new_job): Cache dontcare flag. + * job.c (reap_children): Use cached dontcare flag instead of the + one in struct file. Fixes Savannah bug #15641. + +2006-02-06 Paul D. Smith + + * vpath.c (selective_vpath_search): If the file we find has a + timestamp from -o or -W, use that instead of the real time. + * remake.c (f_mtime): If the mtime is a special token from -o or + -W, don't overwrite it with the real mtime. + Fixes Savannah bug #15341. + + Updates from Markus Mauhart : + + * w32/subproc/sub_proc.c (process_begin): Remove no-op tests. + (process_signal, process_last_err, process_exit_code): Manage + invalid handle values. + (process_{outbuf,errbuf,outcnt,errcnt,pipes}): Unused and don't + manage invalid handles; remove them. + * job.c (start_job_command) [WINDOWS32]: Jump out on error. + * config.h.W32.template [WINDOWS32]: Set flags for Windows builds. + * README.cvs: Updates for building from CVS. + +2006-02-05 Paul D. Smith + + * file.c (enter_file): Keep track of the last double_colon entry, + to avoid walking the list every time we want to add a new one. + Fixes Savannah bug #15533. + * filedef.h (struct file): Add a new LAST pointer. + + * dir.c (directory_contents_hash_cmp): Don't use subtraction to do + the comparison. For 64-bits systems the result of the subtraction + might not fit into an int. Use comparison instead. + Fixes Savannah bug #15534. + + * doc/make.texi: Update the chapter on writing commands to reflect + the changes made in 3.81 for backslash/newline and SHELL handling. + +2006-02-01 Paul D. Smith + + * dir.c (dir_contents_file_exists_p) [WINDOWS32]: Make sure + variable st is not used when it's not initialized. + Patch from Eli Zaretskii . + +2006-01-31 Paul D. Smith + + * README.W32.template: Applied patch #4785 from + Markus Mauhart . + * README.cvs: Applied patch #4786 from + Markus Mauhart . + * make_msvc_net2003.vcproj [WINDOWS32]: New version from + J. Grant . + + * main.c: Update the copyright year in the version output. + * prepare_w32.bat: Remove this file from the distribution. + +2006-01-21 Eli Zaretskii + + * remake.c (update_goal_chain): Set g->changed instead of + incrementing it, as it is only 8-bit wide, and could overflow if + many commands got started in update_file. + + * w32/include/sub_proc.h: Add a prototype for process_used_slots. + + * w32/subproc/sub_proc.c: Change dimension of proc_array[] to + MAXIMUM_WAIT_OBJECTS. + (process_wait_for_any_private): Change dimension of handles[] + array to MAXIMUM_WAIT_OBJECTS. + (process_used_slots): New function. + (process_register): Don't register more processes than the + available number of slots. + (process_easy): Don't start new processes if all slots are used up. + + * job.c (load_too_high, start_waiting_jobs) [WINDOWS32]: If there + are already more children than sub_proc.c can handle, behave as if + the load were too high. + (start_job_command): Fix a typo in error message when process_easy + fails. + +2006-01-14 Eli Zaretskii + + * main.c (main) [WINDOWS32]: Don't refuse to run with -jN, even if + the shell is not sh.exe. + + * job.c (create_batch_file): Renamed from create_batch_filename; + all callers changed. Don't close the temporary file; return its + file descriptor instead. New arg FD allows to return the file + descriptor. + (construct_command_argv_internal): Use _fdopen instead of fopen to + open the batch file. + +2006-01-04 Paul D. Smith + + * readme.vms: Updates for case-insensitive VMS file systems from + Hartmut Becker . + * dir.c (vms_hash): Ditto. + * vmsify.c (copyto): Ditto. + * vmsfunctions.c (readdir): Ditto. + + * make.1: Add a section on the exit codes for make. + + * doc/make.texi: A number of minor updates to the documentation. + +2006-01-03 Paul D. Smith + + * remake.c (update_file_1): Mark a prerequisite changed if it + doesn't exist. + + * read.c (eval): Be sure to strip off trailing whitespace from the + prerequisites list properly. Also, initialize all fields in + struct dep when creating a new one. + +2005-12-28 Paul D. Smith + + * config.h.W32.template [WINDOWS32]: Add in some pragmas to + disable warnings for MSC. + Patch by Rob Tulloh . + +2005-12-17 Eli Zaretskii + + * doc/make.texi (Execution): Add a footnote about changes in + handling of backslash-newline sequences. Mention the differences + on MS-DOS and MS-Windows. + + * NEWS: More details about building the MinGW port and a pointer + to README.W32. Fix the section name that describes the new + backward-incompatible processing of backslash-newline sequences. + The special processing of SHELL set to "cmd" is only relevant to + MS-Windows, not MS-DOS. + +2005-12-17 Eli Zaretskii + + * main.c (handle_runtime_exceptions): Cast exrec->ExceptionAddress + to DWORD, to avoid compiler warnings. + * job.c (exec_command): Cast hWaitPID and hPID to DWORD, and + use %ld in format, to avoid compiler warnings. + + * doc/make.texi (Special Targets): Fix a typo. + (Appending): Fix cross-reference to Setting. + (Special Variables, Secondary Expansion, File Name Functions) + (Flavor Function, Pattern Match, Quick Reference): Ensure two + periods after a sentence. + (Execution): Add @: after "e.g.". + (Environment): Fix punctuation. + (Target-specific, Call Function, Quick Reference): Add @: after "etc." + (Shell Function, Target-specific): Add @: after "vs." + +2005-12-14 Boris Kolpackov + + * read.c (record_target_var): Initialize variable's export field + with v_default instead of leaving it "initialized" by whatever + garbage happened to be on the heap. + +2005-12-12 Paul D. Smith + + * make.1: Fix some display errors and document all existing options. + Patch by Mike Frysinger . + +2005-12-11 Paul D. Smith + + * implicit.c (pattern_search): If 2nd expansion is not set for + this implicit rule, replace the pattern with the stem directly, + and don't re-expand the variable list. Along with the other + .SECONDEXPANSION changes below, fixes bug #13781. + +2005-12-09 Boris Kolpackov + + * implicit.c (pattern_search): Mark other files that this rule + builds as targets so that they are not treated as intermediates + by the pattern rule search algorithm. Fixes bug #13022. + +2005-12-07 Boris Kolpackov + + * remake.c (notice_finished_file): Propagate the change of + modification time to all the double-colon entries only if + it is the last one to be updated. Fixes bug #14334. + +2005-11-17 Boris Kolpackov + + * function.c (func_flavor): Implement the flavor function which + returns the flavor of a variable. + * doc/make.texi (Functions for Transforming Text): Document it. + * NEWS: Add it to the list of new functions. + +2005-11-14 Boris Kolpackov + + * read.c (construct_include_path): Set the .INCLUDE_DIRS special + variable. + * doc/make.texi (Special Variables): Document .INCLUDE_DIRS. + * NEWS: Add .INCLUDE_DIRS to the list of new special variables. + +2005-10-26 Paul Smith + + * read.c (record_files): Don't set deps flags if there are no deps. + * maintMakefile: We only need to build the templates when we are + creating a distribution, so don't do it for "all". + +2005-10-24 Paul D. Smith + + Make secondary expansion optional: its enabled by declaring the + special target .SECONDEXPANSION. + + * NEWS: Update information on second expansion capabilities. + * doc/make.texi (Secondary Expansion): Document the + .SECONDEXPANSION special target and its behavior. + * dep.h (struct dep): Add a flag STATICPATTERN, set to true if the + prerequisite list was found in a static pattern rule. + (free_dep_chain): Declare a prototype. + * file.c (parse_prereqs): New function: break out some complexity + from expand_deps(). + (expand_deps): If we aren't doing second expansion, replace % with + the stem for static pattern rules. Call the new function. + * filedef.h (parse_prereqs): Declare a prototype. + * implicit.c (pattern_search): Initialize the new staticpattern + field. + * main.c (second_expansion): Declare a global variable to remember + if the special target has been seen. Initialize the new + staticpattern field for prerequisites. + * make.h: Extern for second_expansion. + * misc.c (free_dep_chain): New function: frees a struct dep list. + * read.c (read_all_makefiles): Initialize the staticpattern field. + (eval_makefile): Ditto. + (record_files): Check for the .SECONDEXPANSION target and set + second_expansion global if it's found. + Use the new free_dep_chain() instead of doing it by hand. + Set the staticpattern field for prereqs of static pattern targets. + +2005-10-16 Paul D. Smith + + * main.c (main): Set CURDIR to be a file variable instead of a + default, so that values of CURDIR inherited from the environment + won't override the make value. + +2005-09-26 Paul D. Smith + + * job.c (construct_command_argv_internal): If the line is empty + remember to free the temporary argv strings. + Fixes bug # 14527. + +2005-09-16 Paul D. Smith + + * job.c (start_job_command): The noerror flag is a boolean (single + bit); set it appropriately. + Reported by Mark Eichin + +2005-08-29 Paul D. Smith + + * function.c (func_error): On Windows, output from $(info ...) + seems to come in the wrong order. Try to force it with fflush(). + +2005-08-10 Boris Kolpackov + + * read.c (record_files): Move code that sets stem for static + pattern rules out of the if (!two_colon) condition so it is + also executed for two-colon rules. Fixes Savannah bug #13881. + +2005-08-08 Paul D. Smith + + * make.h: Don't test that __STDC__ is non-0. Some compilers + (Windows for example) set it to 0 to denote "ISO C + extensions". + Fixes bug # 13594. + +2005-08-07 Paul D. Smith + + * w32/pathstuff.c (getcwd_fs): Fix warning about assignment in a + conditional (slightly different version of a fix from Eli). + + Fix a bug reported by Michael Matz : patch included. + If make is running in parallel without -k and two jobs die in a + row, but not too close to each other, then make will quit without + waiting for the rest of the jobs to die. + + * main.c (die): Don't reset err before calling reap_children() the + second time: we still want it to be in the error condition. + * job.c (reap_children): Use a static variable, rather than err, + to control whether or not the error message should be printed. + +2005-08-06 Eli Zaretskii + + * w32/subproc/sub_proc.c: Include signal.h. + (process_pipe_io, process_file_io): Pass a pointer to a local + DWORD variable to GetExitCodeProcess. If the exit code is + CONTROL_C_EXIT, put SIGINT into pproc->signal. + + * job.c [WINDOWS32]: Include windows.h. + (main_thread) [WINDOWS32]: New global variable. + (reap_children) [WINDOWS32]: Get the handle for the main thread + and store it in main_thread. + + * commands.c [WINDOWS32]: Include windows.h and w32err.h. + (fatal_error_signal) [WINDOWS32]: Suspend the main thread before + doing anything else. When we are done, close the main thread + handle and exit with status 130. + +2005-07-30 Eli Zaretskii + + * w32/subproc/sub_proc.c (process_begin): Don't pass a NULL + pointer to fprintf. + + * main.c (find_and_set_default_shell): If found a DOSish shell, + set sh_found and the value of default_shell, and report the + findings in debug mode. + + * job.c (construct_command_argv_internal): Check unixy_shell, not + no_default_sh_exe, to decide whether to use Unixy or DOSish + builtin commands. + + * README.W32: Update with info about the MinGW build. + + * build_w32.bat: Support MinGW. + + * w32/subproc/build.bat: Likewise. + + * w32/subproc/sub_proc.c (process_easy): Fix format strings for + printing DWORD args. + + * function.c (windows32_openpipe): Fix format strings for printing + DWORD args. + + * job.c (reap_children) [WINDOWS32]: Don't declare 'status' and + 'reap_mode'. + (start_job_command): Fix format string for printing the result of + process_easy. + (start_job_command) [WINDOWS32]: Do not define. + (exec_command): Fix format string for printing HANDLE args. + + * main.c (handle_runtime_exceptions): Fix sprintf format strings + to avoid compiler warnings. + (open_tmpfile): Declare fd only if HAVE_FDOPEN is defined. + (Note: some of these fixes were submitted independently by J. Grant) + +2005-07-30 J. Grant + + * prepare_w32.bat: Copy config.h.w32 to config.h if not exist. + * make_msvc_net2003.vcproj, make_msvc_net2003.sln: MSVC Project files. + * Makefile.am (EXTRA_DIST): Add MSVC Project files. + +2005-07-15 Paul Smith + + * job.c (construct_command_argv_internal) [DOS,WINDOWS32,OS/2]: If + we don't have a POSIX shell, then revert to the old + backslash-newline behavior (where they are stripped). + Fixes bug #13665. + +2005-07-08 Paul D. Smith + + * config.h.W32.template: Reorder to match the standard config.h, + for easier comparisons. + From J. Grant + + * maintMakefile: Remove .dep_segment before overwriting it, in + case it's not writable or noclobber is set. + * expand.c (variable_expand_string): Cast result of pointer + arithmetic to avoid a warning. + * main.c (switches): Add full-fledged final initializer. + +2005-07-06 Paul D. Smith + + * configure.in: IRIX has _sys_siglist. Tru64 UNIX has __sys_siglist. + * signame.c (strsignal): If we found _sys_siglist[] or + __sys_siglist[] use those instead of sys_siglist[]. + From Albert Chin + +2005-07-04 Paul D. Smith + + * config.h-vms.template [VMS]: Latest VMS has its own glob() and + globfree(); set up to use the GNU versions. + From Martin Zinser + +2005-07-03 Paul D. Smith + + From J. Grant : + + * README.W32.template: Update the Windows and tested MSVC versions. + * NMakefile.template (CFLAGS_any): Change warning level from W3 to W4. + * w32/subproc/NMakefile (CFLAGS_any): Ditto. + * build_w32.bat: Ditto. + * w32/subproc/build.bat: Ditto. + +2005-06-28 Paul D. Smith + + * signame.c: HAVE_DECL_* macros are set to 0, not undef, if the + declaration was checked but not present. + +2005-06-27 Paul D. Smith + + * dir.c (find_directory): Change type of fs_serno/fs_flags/fs_len + to unsigned long. Fixes Savannah bug #13550. + + * w32/subproc/sub_proc.c: Remove (HANDLE) casts on lvalues. + (process_pipe_io): Initialize tStdin/tStdout/tStderr variables. + Fixes Savannah bug #13551. + +2005-06-26 Paul D. Smith + + * make.h: Fix bug in ANSI_STRING/strerror() handling; only define + it if ANSI_STRING is not set. + +2005-06-25 Paul D. Smith + + * read.c (eval): If no filenames are passed to any of the + "include" variants, don't print an error. + * doc/make.texi (Include): Document this. + Fixes Savannah bug #1761. + + * job.c (construct_command_argv_internal): Sanitize handling of + backslash/newline pairs according to POSIX: that is, keep the + backslash-newline in the command script, but remove a following + TAB character, if present. In the fast path, make sure that the + behavior matches what the shell would do both inside and outside + of quotes. In the slow path, quote the backslash and put a + literal newline in the string. + Fixes Savannah bug #1332. + * doc/make.texi (Execution): Document the new behavior and give + some examples. + * NEWS: Make a note of the new behavior. + + * make.h [WINDOWS32]: #include . + Fixes Savannah bug #13478. + + * remake.c (name_mtime): If the stat() of a file fails and the -L + option was given and the file is a symlink, take the best mtime of + the symlink we can get as the mtime of the file and don't fail. + Fixes Savannah bug #13280. + + * read.c (find_char_unquote): Accept a new argument IGNOREVARS. + If it's set, then don't stop on STOPCHARs or BLANKs if they're + inside a variable reference. Make this function static as it's + only used here. + (eval): Call find_char_unquote() with IGNOREVARS set when we're + parsing an unexpanded line looking for semicolons. + Fixes Savannah bug #1454. + * misc.c (remove_comments): Move this to read.c and make it static + as it's only used there. Call find_char_unquote() with new arg. + * make.h: Remove prototypes for find_char_unquote() and + remove_comments() since they're static now. + + * main.c (main): If we see MAKE_RESTARTS in the environment, unset + its export flag and obtain its value. When we need to re-exec, + increment the value and add it into the environment. + * doc/make.texi (Special Variables): Document MAKE_RESTARTS. + * NEWS: Mention MAKE_RESTARTS. + * main.c (always_make_set): New variable. Change the -B option to + set this one instead. + (main): When checking makefiles, only set always_make_flag if + always_make_set is set AND the restarts flag is 0. When building + normal targets, set it IFF always_make_set is set. + (main): Avoid infinite recursion with -W, too: only set what-if + files to NEW before we check makefiles if we've never restarted + before. If we have restarted, set what-if files to NEW _after_ we + check makefiles. + Fixes Savannah bug #7566: + +2005-06-17 Paul D. Smith + + * default.c: Change VMS implicit rules to use $$$$ instead of $$ + in the prerequisites list. + +2005-06-12 Paul D. Smith + + Fix Savannah bug # 1328. + + * configure.in: Check for atexit(). + * misc.c (close_stdout): Test stdout to see if writes to it have + failed. If so, be sure to exit with a non-0 error code. Based on + code found in gnulib. + * make.h: Prototype. + * main.c (main): Install close_stdout() with atexit(). + +2005-06-10 Paul D. Smith + + VMS build updates from Hartmut Becker : + + * vmsjobs.c [VMS]: Updates to compile on VMS: add some missing + headers; make vmsWaitForChildren() static; extern vmsify(). + * job.c [VMS]: Move vmsWaitForChildren() prototype to be global. + Don't create child_execute_job() here (it's in vmsjobs.c). + * makefile.vms (job.obj) [VMS]: Add vmsjobs.c as a prerequisite. + +2005-06-09 Paul D. Smith + + * variable.c (push_new_variable_scope): File variables point + directly to the global_setlist variable. So, inserting a new + scope in front of that has no effect on those variables: they + don't go through current_variable_set_list. If we're pushing a + scope and the current scope is global, push it "the other way" so + that the new setlist is in the global_setlist variable, and + next points to a new setlist with the global variable set. + (pop_variable_scope): Properly undo a push with the new + semantics. + Fixes Savannah bug #11913. + +2005-05-31 Boris Kolpackov + + * job.c (reap_children): Don't die of the command failed but + the dontcare flag is set. Fixes Savannah bug #13216. + + * implicit.c (pattern_search): When creating a target from + an implicit rule match, lookup pattern target and set precious + flag in a newly created target. Fixes Savannah bug #13218. + +2005-05-13 Paul D. Smith + + Implement "if... else if... endif" syntax. + + * read.c (eval): Push all checks for conditional words ("ifeq", + "else", etc.) down into the conditional_line() function. + (conditional_line): Rework to allow "else if..." clause. New + return value -2 for lines which are not conditionals. The + ignoring flag can now also be 2, which means "already parsed a + true branch". If that value is seen no other branch of this + conditional can be considered true. In the else parsing if there + is extra text after the else, invoke conditional_line() + recursively to see if it's another conditional. If not, it's an + error. If so, raise the conditional value to this level instead + of creating a new conditional nesting level. Special check for + "else" and "endif", which aren't allowed on the "else" line. + * doc/make.texi (Conditional Syntax): Document the new syntax. + +2005-05-09 Paul D. Smith + + * Makefile.am (EXTRA_make_SOURCES): Add vmsjobs.c + (MAYBE_W32): Rework how SUBDIRS are handled so that "make dist" + recurses to the w32 directory, even on non-Windows systems. Use + the method suggested in the automake manual. + * configure.in: Add w32/Makefile to AC_CONFIG_FILES. + * maintMakefile (gnulib-url): They moved the texinfo.tex files. + +2005-05-07 Paul D. Smith + + * main.c (die): If we're dying with a fatal error (not that a + command has failed), write back any leftover tokens before we go. + + * job.c (set_child_handler_action_flags): If there are jobs + waiting for the load to go down, set an alarm to go off in 1 + second. This allows us to wake up from a potentially long-lasting + read() and start a new job if the load has gone down. Turn it off + after the read. + (job_noop): Dummy signal handler function. + (new_job): Invoke it with the new semantics. + + * docs/make.texi: Document secondary expansion. Various cleanups + and random work. + +2005-05-03 Paul D. Smith + + Rename .DEFAULT_TARGET to .DEFAULT_GOAL: in GNU make terminology + the targets which are to ultimately be made are called "goals"; + see the GNU make manual. Also, MAKECMDGOALS, etc. + + * filedef.h, read.c, main.c: Change .DEFAULT_TARGET to + .DEFAULT_GOAL, and default_target_name to default_goal_name. + * doc/make.texi (Special Variables): Document .DEFAULT_GOAL. + +2005-05-02 Paul D. Smith + + * job.c, vmsjobs.c (vmsWaitForChildren, vms_redirect, + vms_handle_apos, vmsHandleChildTerm, reEnableAst, astHandler, + tryToSetupYAst, child_execute_job) [VMS]: Move VMS-specific + functions to vmsjobs.c. #include it into jobs.c. + + Grant Taylor reports that -j# can lose + jobserver tokens. I found that this happens when an exported + recursive variable contains a $(shell ...) function reference: in + this situation we could "forget" to write back a token. + + * job.c, job.h: Add variable jobserver_tokens: counts the tokens + we have. It's not reliable to depend on the number of children in + our linked list so keep a separate count. + (new_job): Check jobserver_tokens rather than children && + waiting_jobs. Increment jobserver_tokens when we get one. + (free_child): If jobserver_tokens is 0, internal error. If it's + >1, write a token back to the jobserver pipe (we don't write a + token for the "free" job). Decrement jobserver_tokens. + + * main.c: Add variable master_job_slots. + (main): Set it to hold the number of jobs requested if we're the + master process, when using the jobserver. + (die): Sanity checks: first test jobserver_tokens to make sure + this process isn't holding any tokens we didn't write back. + Second, if master_job_slots is set count the tokens left in the + jobserver pipe and ensure it's the same as master_job_slots (- 1). + +2005-04-24 Paul D. Smith + + Grant Taylor reports that -j# in conjunction + with -l# can lose jobserver tokens, because waiting jobs are not + consulted properly when checking for the "free" token. + + * job.c (free_child): Count waiting_jobs as having tokens. + * job.c (new_job): Ditto. Plus, call start_waiting_jobs() here to + handle jobs waiting for the load to drop. + +2005-04-23 Paul D. Smith + + * main.c (main): Be careful to not core if a variable setting in + the environment doesn't contain an '='. This is illegal but can + happen in broken setups. + Reported by Joerg Schilling . + +2005-04-12 Paul D. Smith + + The second expansion feature causes significant slowdown. Timing + a complex makefile (GCC 4.1) shows a slowdown from .25s to just + read the makefile before the feature, to 11+s to do the same + operations after the feature. Additionally, memory usage + increased drastically. To fix this I added some intelligence that + avoids the overhead of the second expansion unless it's required. + + * dep.h: Add a new boolean field, need_2nd_expansion. + + * read.c (eval): When creating the struct dep for the target, + check if the name contains a "$"; if so set need_2nd_expansion to 1. + (record_files): If there's a "%" in a static pattern rule, it gets + converted to "$*" so set need_2nd_expansion to 1. + + * file.c (expand_deps): Rework to be more efficient. Only perform + initialize_file_variables(), set_file_variables(), and + variable_expand_for_file() if the need_2nd_expansion is set. + + * implicit.c (pattern_search): Default need_2nd_expansion to 0. + (pattern_search): Ditto. + * main.c (handle_non_switch_argument): Ditto. + (main): Ditto. + * read.c (read_all_makefiles): Ditto. + (eval_makefile): Ditto. + +2005-04-07 Paul D. Smith + + * main.c (main) [WINDOWS32]: Export PATH to sub-shells, not Path. + * variable.c (sync_Path_environment): Ditto. + Patch by Alessandro Vesely. Fixes Savannah bug #12209. + + * main.c (main): Define the .FEATURES variable. + * NEWS: Announce .FEATURES. + * doc/make.texi (Special Variables): Document .FEATURES. + + * remake.c (check_dep): If a file is .PHONY, update it even if + it's marked intermediate. Fixes Savannah bug #12331. + +2005-03-15 Boris Kolpackov + + * file.c (expand_deps): Factor out the second expansion and + prerequisite line parsing logic from snap_deps(). + + * file.c (snap_deps): Use expand_deps(). Expand and parse + prerequisites of the .SUFFIXES special target first. Fixes + Savannah bug #12320. + +2005-03-13 Paul D. Smith + + * main.c (main) [MSDOS]: Export SHELL in MSDOS. Requested by Eli + Zaretskii. + +2005-03-11 Paul D. Smith + + * signame.c (strsignal): HAVE_DECL_SYS_SIGLIST is 0 when not + available, not undefined (from Earnie Boyd). + +2005-03-10 Boris Kolpackov + + * implicit.c (pattern_search): Mark an intermediate target as + precious if it happened to be a prerequisite of some (other) + target. Fixes Savannah bug #12267. + +2005-03-09 Paul D. Smith + + * read.c (eval_makefile): Add alloca(0). + (eval_buffer): Ditto. + +2005-03-09 Boris Kolpackov + + * main.c (main): Use o_file instead of o_default when defining + the .DEFAULT_TARGET special variable. + * read.c (eval): Use define_variable_global() instead of + define_variable() when setting new value for the .DEFAULT_TARGET + special variable. Fixes Savannah bug #12266. + +2005-03-04 Boris Kolpackov + + * imlicit.c (pattern_search): Mark files for which an implicit + rule has been found as targets. Fixes Savannah bug #12202. + +2005-03-04 Paul D. Smith + + * AUTHORS: Update. + * doc/make.texi (Automatic Variables): Document $|. + +2005-03-03 Boris Kolpackov + + * read.c (record_files): Instead of substituting % with + actual stem value in dependency list replace it with $*. + This fixes stem triple expansion bug. + + * implicit.c (pattern_search): Copy stem to a separate + buffer and make it a properly terminated string. Assign + this buffer instead of STEM (which is not terminated) to + f->stem. Instead of substituting % with actual stem value + in dependency list replace it with $*. This fixes stem + triple expansion bug. + +2005-03-01 Paul D. Smith + + * commands.c (fatal_error_signal) [WINDOWS32]: Don't call kill() + on Windows, as it takes a handle not a pid. Just exit. + Fix from patch #3679, provided by Alessandro Vesely. + + * configure.in: Update check for sys_siglist[] from autoconf manual. + * signame.c (strsignal): Update to use the new autoconf macro. + +2005-03-01 Boris Kolpackov + + * read.c (record_files): Add a check for the list of prerequisites + of a static pattern rule being empty. Fixes Savannah bug #12180. + +2005-02-28 Paul D. Smith + + * doc/make.texi (Text Functions): Update docs to allow the end + ordinal for $(wordlist ...) to be 0. + * function.c (func_wordlist): Fail if the start ordinal for + $(wordlist ...) is <1. Matches documentation. + Resolves Savannah support request #103195. + + * remake.c (update_goal_chain): Fix logic for stopping in -q: + previously we were stopping when !-q, exactly the opposite. This + has been wrong since version 1.34, in 1994! + (update_file): If we got an error don't break out to run more + double-colon rules: just return immediately. + Fixes Savannah bug #7144. + +2005-02-27 Paul D. Smith + + * misc.c (end_of_token): Make argument const. + * make.h: Update prototype. + + * function.c (abspath, func_realpath, func_abspath): Use + PATH_VAR() and GET_PATH_MAX instead of PATH_MAX. + * dir.c (downcase): Use PATH_VAR() instead of PATH_MAX. + * read.c (record_files): Ditto. + * variable.c (do_variable_definition): Ditto. + + * function.c (func_error): Create a new function $(info ...) that + simply prints the message to stdout with no extras. + (function_table_init): Add new function to the table. + * NEWS: Add $(info ...) reference. + * doc/make.texi (Make Control Functions): Document it. + + New feature: if the system supports symbolic links, and the user + provides the -L/--check-symlink-time flag, then use the latest + mtime between the symlink(s) and the target file. + + * configure.in (MAKE_SYMLINKS): Check for lstat() and + readlink(). If both are available, define MAKE_SYMLINKS. + * main.c: New variable: check_symlink_flag. + (usage): Add a line for -L/--check-symlink-times to the help string. + (switches): Add -L/--check-symlink-times command line argument. + (main): If MAKE_SYMLINKS is not defined but the user specified -L, + print a warning and disable it again. + * make.h: Declare check_symlink_flag. + * remake.c (name_mtime): If MAKE_SYMLINKS and check_symlink_flag, + if the file is a symlink then check each link in the chain and + choose the NEWEST mtime we find as the mtime for the file. The + newest mtime might be the file itself! + * NEWS: Add information about this new feature. + * doc/make.texi (Options Summary): Add -L/--check-symlink-times docs. + + Avoid core dumps described in Savannah bug # 12124: + + * file.c: New variable snapped_deps remember whether we've run + snap_deps(). + (snap_deps): Set it. + * filedef.h: Extern it. + * read.c (record_files): Check snapped_deps; if it's set then + we're trying to eval a new target/prerequisite relationship from + within a command script, which we don't support. Fatal. + +2005-02-28 Boris Kolpackov + + Implementation of the .DEFAULT_TARGET special variable. + + * read.c (eval): If necessary, update default_target_name when + reading rules. + * read.c (record_files): Update default_target_file if + default_target_name has changed. + * main.c (default_target_name): Define. + * main.c (main): Enter .DEFAULT_TARGET as make variable. If + default_target_name is set use default_target_file as a root + target to make. + * filedef.h (default_target_name): Declare. + * dep.h (free_dep_chain): + * misc.c (free_dep_chain): Change to operate on struct nameseq + and change name to free_ns_chain. + * file.c (snap_deps): Update to use free_ns_chain. + +2005-02-27 Boris Kolpackov + + Implementation of the second expansion in explicit rules, + static pattern rules and implicit rules. + + * read.c (eval): Refrain from chopping up rule's dependencies. + Store them in a struct dep as a single dependency line. Remove + the code that implements SySV-style automatic variables. + + * read.c (record_files): Adjust the code that handles static + pattern rules to expand all percents instead of only the first + one. Reverse the order in which dependencies are stored so that + when the second expansion reverses them again they appear in + the makefile order (with some exceptions, see comments in + the code). Remove the code that implements SySV-style automatic + variables. + + * file.c (snap_deps): Implement the second expansion and chopping + of dependency lines for explicit rules. + + * implicit.c (struct idep): Define an auxiliary data type to hold + implicit rule's dependencies after stem substitution and + expansion. + + * implicit.c (free_idep_chain): Implement. + + * implicit.c (get_next_word): Implement helper function for + parsing implicit rule's dependency lines into words taking + into account variable expansion requests. Used in the stem + splitting code. + + * implicit.c (pattern_search): Implement the second expansion + for implicit rules. Also fixes bug #12091. + + * commands.h (set_file_variables): Declare. + * commands.c (set_file_variables): Remove static specifier. + + * dep.h (free_dep_chain): Declare. + * misc.c (free_dep_chain): Implement. + + * variable.h (variable_expand_for_file): Declare. + * expand.c (variable_expand_for_file): Remove static specifier. + + * make.h (strip_whitespace): Declare. + * function.c (strip_whitespace): Remove static specifier. + +2005-02-26 Paul D. Smith + + * main.c (main): Check for ferror() when reading makefiles from stdin. + Apparently some shells in Windows don't close pipes properly and + require this check. + +2005-02-24 Jonathan Grant + + * configure.in: Add MinGW configuration options, and extra w32 code + directory. + * Makefile.am: Add MinGW configuration options, and extra w32 code + directory. + * main.c: Determine correct program string (after last \ without .exe). + * subproc/sub_proc.c: `GetExitCodeProcess' from incompatible pointer + type fix x2 + * w32/Makefile.am: Import to build win32 lib of sub_proc etc. + * subproc/w32err.c: MSVC thread directive not applied to MinGW builds. + * tests/run_make_tests.pl, tests/test_driver.pl: MSYS testing + environment support. + +2004-04-16 Dmitry V. Levin + + * function.c (func_shell): When initializing error_prefix, check + that reading file name is not null. This fixes long-standing + segfault in cases like "make 'a1=$(shell :)' 'a2:=$(a1)'". + +2005-02-09 Paul D. Smith + + * maintMakefile: Update the CVS download URL to simplify them. + Also, the ftp://ftp.gnu.org/GNUinfo site was removed so I'm + downloading the .texi files from Savannah now. + + Fixed these issues reported by Markus Mauhart : + + * main.c (handle_non_switch_argument): Only add variables to + command_variables if they're not already there: duplicate settings + waste space and can be confusing to read. + + * w32/include/sub_proc.h: Remove WINDOWS32. It's not needed since + this header is never included by non-WINDOWS32 code, and it + requires to define which isn't always included first. + + * dir.c (read_dirstream) [MINGW]: Use proper macro names when + testing MINGW32 versions. + + * main.c (log_working_directory): flush stdout to be sure the WD + change is printed before any stderr messages show up. + +2005-02-01 Paul D. Smith + + * maintMakefile (po_repo): Update the GNU translation site URL. + +2004-12-01 Paul D. Smith + + * main.c (main): Change char* env_shell to struct variable shell_var. + * variable.c (target_environment): Use new shell_var. + +2004-11-30 Paul D. Smith + + * configure.in: The old way we avoided creating build.sh from + build.sh.in before build.sh.in exists doesn't work anymore; we + have to use raw M4 (thanks to Andreas Schwab for + the help!). This also keeps automake from complaining. + * Makefile.am (README): Add a dummy target so automake won't + complain that this file doesn't exist when we checkout from CVS. + * maintMakefile (.dep_segment): Rewrite this rule since newer + versions of automake don't provide DEP_FILES. + +2004-11-30 Boris Kolpackov + + Implementation of `realpath' and `abspath' built-in functions. + + * configure.in: Check for realpath. + * function.c (abspath): Return an absolute file name that does + not contain any `.' or `..' components, nor repeated `/'. + * function.c (func_abspath): For each name call abspath. + * function.c (func_realpath): For each name call realpath + from libc or delegate to abspath if realpath is not available. + * doc/make.texi (Functions for File Names): Document new functions. + * doc/make.texi (Quick Reference): Ditto. + +2004-11-28 Paul D. Smith + + * main.c (main) [WINDOWS32]: Remove any trailing slashes from -C + arguments. Fixes bug #10252. + + Fix for bug #1276: Handle SHELL according to POSIX requirements. + + * main.c (main): Set SHELL to v_noexport by default. Remember the + original environment setting of SHELL in the env_shell variable. + * main.h: Export new env_shell variable. + * variable.c (target_environment): If we find a v_noexport + variable for SHELL, add a SHELL variable with the env_shell value. + * doc/make.texi (Quick Reference): Document the POSIX behavior. + * doc/make.texi (Variables/Recursion): Ditto. + +2004-11-28 Paul D. Smith + + * main.c (find_and_set_default_shell) [WINDOWS32]: check for + equality of "cmd"/"cmd.exe", not inequality. Fixes bug #11155. + Patch by Alessandro Vesely. + +2004-11-12 Paul D. Smith + + * job.c (child_execute_job) [VMS]: Don't treat "#" as a comment on + the command line if it's inside a string. + Patch by: Hartmut Becker + +2004-10-21 Boris Kolpackov + + * function.c (func_lastword): New function: return last word + from the list of words. + * doc/make.texi: Document $(lastword ). Fix broken links in + Quick Reference section. + +2004-10-06 Paul D. Smith + + Apply patch from Alessandro Vesely, provided with bug # 9748. + Fix use of tmpnam() to work with Borland C. + + * job.c (construct_command_argv_internal) [WINDOWS32]: Remove + construction of a temporary filename, and call new function + create_batch_filename(). + (create_batch_filename) [WINDOWS32]: New function to create a + temporary filename. + +2004-10-05 Boris Kolpackov + + * read.c (record_target_var): Expand simple pattern-specific + variable. + * variable.c (initialize_file_variables): Do not expand simple + pattern-specific variable. + +2004-09-28 Boris Kolpackov + + * remake.c (update_file_1): When rebuilding makefiles inherit + dontcare flag from a target that triggered update. + +2004-09-27 Boris Kolpackov + + * variable.c (initialize_file_variables): Mark pattern-specific + variable as a per-target and copy export status. + +2004-09-21 Boris Kolpackov + + * file.c (snap_deps): Mark .PHONY prerequisites as targets. + + * implicit.c (pattern_search): When considering an implicit rule's + prerequisite check that it is actually a target rather then + just an entry in the file hashtable. + +2004-09-21 Paul D. Smith + + * read.c (readstring): Fix some logic errors in backslash handling. + (eval): Remove some unnecessary processing in buffer handling. + (record_target_var): Assert that parse_variable_definition() succeeded. + Reported by: Markus Mauhart . + + * misc.c: Removed the sindex() function. All instances of this + function were trivially replaceable by the standard strstr() + function, and that function will always have better (or certainly + no worse) performance than the very simple-minded algorithm + sindex() used. This can matter with complex makefiles. + * make.h: Remove the prototype for sindex(). + * function.c (subst_expand): Convert sindex() call to strstr(). + This means we no longer need to track the TLEN value so remove that. + (func_findstring): Convert sindex() to strstr(). + * commands.c (chop_commands): Convert sindex() calls to strstr(). + Suggested by: Markus Mauhart . + + * main.c (find_and_set_default_shell) [WINDOWS32]: Implement the + idea behind Savannah Patch #3144 from david.baird@homemail.com. + If SHELL is set to CMD.EXE then assume it's batch-mode and + non-unixy. I wrote the code differently from the patch, though, + to make it safer. This also resolves bug #9174. + +2004-09-20 Paul D. Smith + + * expand.c (variable_expand_string): Modify to invoke + patsubst_expand() instead of subst_expand(); the latter didn't + handle suffix patterns correctly. + * function.c (subst_expand): Remove the SUFFIX_ONLY parameter; it + was used only from variable_expand_string() and is no longer used + there. + (func_subst): Ditto, on call to subst_expand(). + (patsubst_expand): Require the percent pointers to point to the + character after the %, not to the % itself. + * read.c (record_files): New call criteria for patsubst_expand(). + * variable.h: Remove SUFFIX_ONLY from subst_expand() prototype. + This is to fix a bug reported by Markus Mauhart . + +2004-09-19 Paul D. Smith + + * function.c (subst_expand): Fix a check in by_word: look for a + previous blank if we're beyond the beginning of the string, not + the beginning of the word. + Bugs reported by Markus Mauhart . + +2004-05-16 Paul D. Smith + + * remake.c (update_goal_chain): Change the argument specifying + whether we're rebuilding makefiles to be a global variable, + REBUILDING_MAKEFILES. + (complain): Extract the code that complains about no rules to make + a target into a separate function. + (update_file_1): If we tried to rebuild a file during the makefile + rebuild phase and it was dontcare, then no message was printed. + If we then try to build the same file during the normal build, + print a message this time. + (remake_file): Don't complain about un-remake-able files when + we're rebuilding makefiles. + +2004-05-11 Paul D. Smith + + * job.c (construct_command_argv_internal): OS/2 patches from + Andreas Buening . + +2004-05-10 Paul D. Smith + + * remake.c (update_file): Don't walk the double-colon chain unless + this is a double-colon rule. Fix suggested by Boris Kolpackov + . + + * makefile.vms (CFLAGS): Remove glob/globfree (see readme.vms docs) + * readme.vms: New section describing OpenVMS support and issues. + * default.c (default_variables): Add support for IA64. + * job.c (tryToSetupYAst) [VMS]: On VMS running make in batch mode + without some privilege aborts make with the error + %SYSTEM-F-NOPRIV. It happens when setting up a handler for + pressing Ctrl+Y and the input device is no terminal. The change + catches this error and just continues. + + Patches by Hartmut Becker + +2004-04-25 Paul D. Smith + + * commands.c (set_file_variables): Set $< properly in the face of + order-only prerequisites. + Patch from Boris Kolpackov + +2004-04-21 Bob Byrnes + + * main.c (main): Notice failures to remake makefiles. + +2004-03-28 Paul D. Smith + + Patches for Acorn RISC OS by Peter Naulls + + * job.c: No default shell for RISC OS. + (load_too_high): Hard-code the return to 1. + (construct_command_argv_internal): No sh_chars or sh_cmds. + * getloadavg.c: Don't set LOAD_AVE_TYPE on RISC OS. + +2004-03-20 Paul D. Smith + + * variable.c (do_variable_definition): Don't append from the + global set if a previous non-appending target-specific variable + definition exists. Reported by Oliver Schmidt + (with fix). + + * expand.c (reference_variable): Don't give up on variables with + no value that have the target-specific append flag set: they might + have a value after all. Reported by Oliver Schmidt + (with fix) and also by Maksim A. Nikulin + . + + * rule.c (count_implicit_rule_limits): Don't delete patterns which + refer to absolute pathnames in directories that don't exist: some + portion of the makefile could create those directories before we + match the pattern. Fixes bugs #775 and #108. + + Fixes from Jonathan R. Grant : + + * main.c (main): Free makefile_mtimes if we have any. + * README.W32.template: Update documentation for the current status + of the MS-Windows port. + * NMakefile.template (MAKE): Add "MAKE = nmake". A conflicting + environment variable is sometimes already defined which causes the + build to fail. + * main.c (debug_signal_handler): Only define this function if + SIGUSR1 is available. + + Fixes for OS/2 from Andreas Beuning : + + * configure.in [OS/2]: Relocate setting of HAVE_SA_RESTART for OS/2. + * README.OS2.template: Documentation updates. + * build.template: Add LIBINTL into LOADLIBES. Add $CFLAGS to the + link line for safety. + * maintMakefile (build.sh.in): Remove an extraneous ")". + * job.c (child_execute_job): Close saved FDs. + * job.c (exec_command) [OS/2]: exec_command(): If the command + can't be exec'ed and if the shell is not Unix-sh, then try again + with argv = { "cmd", "/c", ... }. Normally, this code is never + reached for the cmd shell unless the command really doesn't exist. + (construct_command_argv_internal) [OS/2]: The code for cmd + handling now uses new_argv = { "cmd", "/c", "original line", NULL}. + The CMD builtin commands are case insensitive so use strcasecmp(). + +2004-03-19 Paul D. Smith + + * read.c (do_define): Re-order line counter increment so the count + is accurate (we were losing one line per define). Reported by + Dave Yost . + +2004-03-06 Paul D. Smith + + * configure.in (HAVE_ANSI_COMPILER): Define if we have an ANSI/ISO + compiler. + * make.h: Convert uses of __STDC__ to HAVE_ANSI_COMPILER. + * misc.c (message,error,fatal): Ditto. + * configh.dos.template: Define HAVE_ANSI_COMPILER. + * config.h.W32.template: Ditto. + * config.h-vms.template: Ditto. + * config.ami.template: Ditto. + +2004-03-04 Paul D. Smith + + * README.template: Add a note about broken /bin/sh on SunOS + 4.1.3_U1 & 4.1.4. Fix up Savannah links. + + * misc.c (message, error, fatal): Don't use "..." if we're using + varargs. ansi2knr should handle this but it doesn't work: it + translates "..." to va_dcl etc. but _AFTER_ the preprocessor is + done. On many systems (SunOS for example) va_dcl is a #define. + So, force the use of the non-"..." version on pre-ANSI compilers. + + * maintMakefile (sign-dist): Create some rules to help automate + the new GNU ftp upload method. + +2004-02-24 Paul D. Smith + + * config.h.W32.template: Add HAVE_STDARG_H + * config.h-vms.template: Ditto. + * config.ami.template: Ditto. + +2004-02-23 Jonathan Grant + + * README.W32.template: Add a notation about -j with BATCH_MODE_ONLY. + * build_w32.bat: Remove extra "+". + +2004-02-23 Paul D. Smith + + * make.h: Create an UNUSED macro to mark unused parameters. + * (many): Clean up warnings by applying UNUSED, fixing + signed/unsigned incompatibilities, etc. + + * acinclude.m4 (AC_STRUCT_ST_MTIM_NSEC): Add quoting to silence + autoconf warnings. + * filedef.h: Name the command_state enumeration. + * file.c (set_command_state): Use the enumeration in the function + argument. + + * configure.in: Explicitly set SET_MAKE to empty, to disable + MAKE=make even when no make already exists. Fix bug #3823. + +2004-02-22 Paul D. Smith + + * maintMakefile: Perl script to clean up all non-CVS files. Use + it on all the subdirectories for the cvs-clean target. + + * main.c (decode_switches): Require non-empty strings for all our + string command-line options. Fixes Debian bug # 164165. + + * configure.in: Check for stdarg.h and varargs.h. + * make.h (USE_VARIADIC): Set this if we can use variadic functions + for printing messages. + * misc.c: Check USE_VARIADIC instead of (obsolete) HAVE_STDVARARGS. + (message): Ditto. + (error): Ditto. + (fatal): Ditto. + + A number of patches for OS/2 support from Andreas Buening + : + + * job.c (child_handler) [OS/2]: Allow this on OS/2 but we have to + disable the SIGCHLD handler. + (reap_children) [OS/2]: Remove special handling of job_rfd. + (set_child_handler_action_flags) [OS/2]: Use this function in OS/2. + (new_job) [OS/2]: Disable the SIGCHLD handler on OS/2. + * main.c (main) [OS/2]: Special handling for paths in OS/2. + * configure.in [OS/2]: Force SA_RESTART for OS/2. + * Makefile.am (check-regression): Use $(EXEEXT) for Windows-type + systems. + +2004-02-21 Paul D. Smith + + * w32/subproc/sub_proc.c (process_easy) [W32]: Christoph Schulz + reports that if process_begin() fails we don't + handle the error condition correctly in all cases. + * w32/subproc/w32err.c (map_windows32_error_to_string): Make sure + to have a newline on the message. + + * job.c (construct_command_argv_internal): Add "test" to UNIX + sh_cmds[]. Fixes Savannah bug # 7606. + +2004-02-04 Paul D. Smith + + * job.c (vms_handle_apos) [VMS]: Fix various string handling + situations in VMS DCL. Fixes Savannah bug #5533. Fix provided by + Hartmut Becker . + +2004-01-21 Paul D. Smith + + * job.c (load_too_high): Implement an algorithm to control the + "thundering herd" problem when using -l to control job creation + via the load average. The system only recomputes the load once a + second but we can start many jobs in a second. To solve this we + keep track of the number of jobs started in the last second and + apply a weight to try to guess what a correct load would be. + The algorithm was provided by Thomas Riedl . + Also fixes bug #4693. + (reap_children): Decrease the job count for this second. + (start_job_command): Increase the job count for this second. + + * read.c (conditional_line): Expand the text after ifn?def before + checking to see if it's a single word. Fixes bug #7257. + +2004-01-09 Paul D. Smith + + * file.c (print_file): Recurse to print all targets in + double-colon rules. Fixes bug #4518, reported (with patch) by + Andrew Chatham . + +2004-01-07 Paul D. Smith + + * acinclude.m4: Remove make_FUNC_SETVBUF_REVERSED. + * configure.in: Change make_FUNC_SETVBUF_REVERSED to + AC_FUNC_SETVBUF_REVERSED. + + * doc/make.texi (Target-specific): Fix Savannah bug #1772. + (MAKE Variable): Fix Savannah bug #4898. + + * job.c (construct_command_argv_internal): Add "!" to the list of + shell escape chars. POSIX sh allows it to appear before a + command, to negate the exit code. Fixes bug #6404. + + * implicit.c (pattern_search): When matching an implicit rule, + remember which dependencies have the ignore_mtime flag set. + Original fix provided in Savannah patch #2349, by Benoit + Poulot-Cazajous . + +2003-11-22 Paul D. Smith + + * README.W32.template (Outputs): Clarification on -j with + BATCH_MODE_ONLY_SEHLL suggested by Jonathan R. Grant + . + +2003-11-02 Paul D. Smith + + * function.c (func_if): Strip all the trailing whitespace from the + condition, then don't expand it. Fixed bug # 5798. + + * expand.c (recursively_expand_for_file): If we're expanding a + variable with no file context, then use the variable's context. + Fixes bug # 6195. + +2003-10-21 Paul D. Smith + + * main.c (log_working_directory): Add newlines to printf()s. + + * README.cvs: Add a note to ignore warnings during autoreconf. + + * maintMakefile (po_repo): Set a new URL for PO file updates. + (get-config/config.guess get-config/config.sub): Get these files + from the Savannah config project instead of ftp.gnu.org. + +2003-10-05 Paul Eggert + + * main.c (main): Avoid potential subscript error if environ has + short strings. + +2003-08-22 Paul D. Smith + + * misc.c (xmalloc, xrealloc): Add one to 0 sizes, to cater to + systems which don't yet implement the C89 standard :-/. + +2003-07-18 Paul D. Smith + + * dir.c (directory_contents_hash_1, directory_contents_hash_1) + [WINDOWS32]: Initialize hash. + +2003-06-19 Earnie Boyd + + * dir.c (read_dirstream): Provide a workaround for broken versions of + the MinGW dirent structure. + +2003-05-30 Earnie Boyd + + * w32/include/dirent.h: Add __MINGW32__ filter. + +2003-05-30 Earnie Boyd + + * make.h: Add global declaration of *make_host. + * main.c (print_usage): Remove local declaration of *make_host. + (print_version): Display "This program built for ..." after Copyright + notice. + +2003-05-30 Earnie Boyd + + * doc/make.texi: Change "ifinfo" to "ifnottex" as suggested by the + execution of "makeinfo --html make.texi". + +2003-04-30 Paul D. Smith + + * build.template: Make some changes to maybe allow this script to + work on DOS/Windows/OS2 systems. Suggested by Andreas Buening. + + * README.OS2.template: New file for OS/2 support. Original + contributed by Andreas Buening. + * configure.in: Invoke new pds_AC_DOS_PATHS macro to test for + DOS-style paths. + +2003-04-19 Paul D. Smith + + Fix bug #1405: allow a target to match multiple pattern-specific + variables. + + * rule.c (create_pattern_var, lookup_pattern_var): Move these to + variable.c, where they've always belonged. + * rule.h: Move the prototypes and struct pattern_var as well. + * variable.c (initialize_file_variables): Invoke + lookup_pattern_var() in a loop, until no more matches are found. + If a match is found, create a new variable set for the target's + pattern variables. Then merge the contents of each matching + pattern variable set into the target's pattern variable set. + (lookup_pattern_var): Change this function to be usable + in a loop. It takes a starting position: if NULL, start at the + beginning; if non-NULL, start with the pattern variable after that + position, and return the next matching pattern. + (create_pattern_var): Create a unique instance of + pattern-specific variables for every definition in the makefile. + Don't combine the same pattern together. This allows us to + process the variable handling properly even when the same pattern + is used multiple times. + (parse_variable_definition): New function: break out the parsing + of a variable definition line from try_variable_definition. + (try_variable_definition): Call parse_variable_definition to + parse. + (print_variable_data_base): Print out pattern-specific variables. + * variable.h (struct variable): Remember when a variable is + conditional. Also remember its flavor. + (struct pattern_var): Instead of keeping a variable set, we just + keep a single variable for each pattern. + * read.c (record_target_var): Each pattern variable contains only a + single variable, not a set, so create it properly. + * doc/make.texi (Pattern-specific): Document the new behavior. + +2003-04-17 Paul D. Smith + + * dir.c (file_exists_p) [VMS]: Patch provided with Bug #3018 by + Jean-Pierre Portier . I don't understand the + file/directory naming rules for VMS so I can't tell whether this + is correct or not. + +2003-04-09 Paul D. Smith + + * configure.in (HAVE_DOS_PATHS): Define this on systems that need + DOS-style pathnames: backslash separators and drive specifiers. + +2003-03-28 Paul D. Smith + + * file.c (snap_deps): If .SECONDARY with no targets is given, set + the intermediate flag on all targets. Fixes bug #2515. + +2003-03-24 Paul D. Smith + + * configure.in, Makefile.am, glob/Makefile.am, doc/Makefile.am: + Upgrade to autoconf 2.57 and automake 1.7.3. + + * job.c: More OS/2 changes from Andreas Buening. + + * file.c (print_file): Fix variable initialization. + Fixes bug #2892. + + * remake.c (notice_finished_file): + + * make.h (ENULLLOOP): Set errno = 0 before invoking the command; + some calls (like readdir()) return NULL in valid situations + without resetting errno. Fixes bug #2846. + +2003-02-25 Paul D. Smith + + Port to OS/2 (__EMX__) by Andreas Buening . + + * job.c (_is_unixy_shell) [OS/2]: New function. + Set default shell to /bin/sh. + (reap_children): Close the job_rfd pipe here since we don't use a + SIGCHLD handler. + (set_child_handler_action_flags): define this to empty on OS/2. + (start_job_command): Close the jobserver pipe and use + child_execute_job() instead of fork/exec. + (child_execute_job): Rewrite to handle stdin/stdout FDs and spawn + rather than exec'ing, then reconfigure stdin/stdout. + (exec_command): Rewrite to use spawn instead of exec. Return the + PID of the child. + + * main.c (main) [OS/2]: Call initialize_main(). Handle argv[0] as + in DOS. Handle the TEMP environment variable as in DOS. Don't + use a SIGCHLD handler on OS/2. Choose a shell as in DOS. Don't + use -j in DOS mode. Use child_execute_job() instead of + exec_command(). + + * function.c (func_shell) [OS/2]: Can't use fork/exec on OS/2: use + spawn() instead. + + * job.h [OS/2]: Move CLOSE_ON_EXEC here from job.c. Add + prototypes that return values. + + * remake.c (f_mtime) [OS/2]: Handle FAT timestamp offsets for OS/2. + + * read.c (readline) [OS/2]: Don't handle CRLF specially on OS/2. + * default.c (default_suffixes) [OS/2]: Set proper default suffixes + for OS/2. + * vpath.c (construct_vpath_list) [OS/2]: Handle OS/2 paths like + DOS paths. + +2003-02-24 Paul D. Smith + + * default.c [VMS]: New default rules for .cxx -> .obj compiles. + * job.c (child_execute_job) [VMS]: New code for handling spawn(). + (child_execute_job) [VMS]: Handle error status properly. + Patches provided by Hartmut Becker . + + * function.c (func_shell): Use EINTRLOOP() while reading from the + subshell pipe (Fixes bug #2502). + * job.c (free_child): Use EINTRLOOP() while writing tokens to the + jobserver pipe. + * main.c (main): Ditto. + +2003-01-30 Paul D. Smith + + * read.c (eval): eval() was not fully reentrant, because the + collapsed buffer was static. Change it to be an automatic + variable so that eval() can be invoked recursively. + Fixes bug # 2238. + (eval): Apply patch # 1022: fix memory reference error on long + target-specific variable lines. + Patch provided by Steve Brown . + + * function.c (check_numeric): Combine the is_numeric() function + into this function, since it's only called from one place. + Constify this function. Have it print the incorrect string in the + error message. Fixes bug #2407. + (strip_whitespace): Constify. + (func_if): Constify. + * expand.c (expand_argument): Constify. + +2003-01-29 Paul D. Smith + + Fix bug # 2169, also reported by other people on various systems. + + * make.h: Some systems, such as Solaris and PTX, do not fully + implement POSIX-compliant SA_RESTART functionality; important + system calls like stat() and readdir() can still fail with EINTR + even if SA_RESTART has been set on the signal handler. So, + introduce macros EINTRLOOP() and ENULLLOOP() which can loop on + EINTR for system calls which return -1 or 0 (NULL), respectively, + on error. + Also, remove the old atomic_stat()/atomic_readdir() and + HAVE_BROKEN_RESTART handling. + + * configure.in: Remove setting of HAVE_BROKEN_RESTART. + + * arscan.c (ar_member_touch): Use EINTRLOOP() to wrap fstat(). + * remake.c (touch_file): Ditto. + + * commands.c (delete_target): Use EINTRLOOP() to wrap stat(). + * read.c (construct_include_path): Ditto. + * remake.c (name_mtime): Ditto. + * vpath.c (selective_vpath_search): Ditto. + * dir.c (find_directory): Ditto. + (local_stat): Ditto. + (find_directory): Use ENULLLOOP() to wrap opendir(). + (dir_contents_file_exists_p): Use ENULLLOOP() to wrap readdir(). + + * misc.c: Remove HAVE_BROKEN_RESTART, atomic_stat(), and + atomic_readdir() handling. + +2003-01-22 Paul D. Smith + + * function.c (func_call): Fix Bug #1744. If we're inside a + recursive invocation of $(call ...), mask any of the outer + invocation's arguments that aren't used by this one, so that this + invocation doesn't "inherit" them accidentally. + +2002-12-05 Paul D. Smith + + * function.c (subst_expand): Valery Khamenia reported a + pathological performance hit when doing substitutions on very + large values with lots of words: turns out we were invoking + strlen() a ridiculous number of times. Instead of having each + call to sindex() call strlen() again, keep track of how much of + the text we've seen and pass the length to sindex(). + +2002-11-19 Paul D. Smith + + * README.cvs, configure.in: Upgrade to require autoconf 2.56. + + +2002-11-16 Paul D. Smith + + * NMakefile.template (OBJS): Add hash.c object file. + * SMakefile.template (srcs): Ditto. + * Makefile.ami (objs): Ditto. + * build_w32.bat: Ditto. + + * Makefile.DOS.template: Remove extra dependencies. + +2002-10-25 Paul D. Smith + + * expand.c (install_variable_buffer): New function. Install a new + variable_buffer context and return the previous one. + (restore_variable_buffer): New function. Free the current + variable_buffer context and put a previously saved one back. + * variable.h: Prototypes for {install,restore}_variable_buffer. + * function.c (func_eval): Push a new variable_buffer context + before we eval, then restore the old one when we're done. + Fixes Bug #1517. + + * read.c (install_conditionals): New function. Install a new + conditional context and return the previous one. + (restore_conditionals): New function. Free the current + conditional context and put a previously saved one back. + (eval): Use the {install,restore}_conditionals for "include" + handling. + (eval_buffer): Use {install,restore}_conditionals to preserve the + present conditional state before we evaluate the buffer. + Fixes Bug #1516. + + * doc/make.texi (Quick Reference): Add references to $(eval ...) + and $(value ...). + (Recursion): Add a variable index entry for CURDIR. + + * README.cvs: Update to appropriate versions. + * Makefile.am (nodist_loadavg_SOURCES): automake gurus point out I + don't need to copy loadavg.c: automake is smart enough to create + it for me. Still have a bug in automake related to ansi2knr tho. + +2002-10-14 Paul D. Smith + + * remake.c (notice_finished_file): Only touch targets if they have + at least one command (as per POSIX). Resolve Bug #1418. + + * *.c: Convert to using ANSI C-style function definitions. + * Makefile.am: Enable the ansi2knr feature of automake. + * configure.in: ditto. + +2002-10-13 Paul D. Smith + + * commands.c (set_file_variables): Bug #1379: Don't use alloca() + for automatic variable values like $^, etc. In the case of very + large lists of prerequisites this causes problems. Instead reuse + a static buffer (resizeable) for each variable. + + * read.c (eval): Fix Bug #1391: allow "export" keyword in + target-specific variable definitions. Check for it and set an + "exported" flag. + (record_target_var): Set the export field to v_export if the + "exported" flag is set. + * doc/make.texi (Target-specific): Document the ability to use + "export". + + * doc/make.texi: Change the name of the section on automatic + variables from "Automatic" to "Automatic Variables". Added text + clarifying the scope of automatic variables. + +2002-10-04 Paul D. Smith + + * read.c (eval): Allow SysV $$@ variables to use {} braces as well + as () braces. + (record_files): Ditto. + + * expand.c (variable_expand_string): In $(A:x=y) expansion limit + the search for the '=' to only within the enclosing parens. + +2002-10-03 Paul D. Smith + + Version 3.80 released. + + * dir.c: Change hash functions to use K&R function definition style. + * function.c: Ditto. + * read.c: Ditto. + * variable.c: Ditto. + + Update to automake 1.7. + + * Makefile.am (AUTOMAKE_OPTIONS): Update to require 1.7. + (pdf): Remove this target as automake now provides one. + + * configure.in: Change AM_CONFIG_HEADER to AC_CONFIG_HEADERS. + +2002-09-30 Martin P.J. Zinser + + * makefile.com: Updates for GNU make 3.80. + * makefile.vms: Ditto. + +2002-09-23 Paul D. Smith + + * read.c (enum make_word_type): Remove w_comment. + (get_next_mword): Don't treat comment characters as special; where + this function is used we will never see a comment (it's stripped + before we get here) and treating comments specially means that + targets like "foo\#bar" aren't handled properly. + +2002-09-18 Paul D. Smith + + * doc/make.texi (Bugs): Update with some info on Savannah, etc. + + * read.c (eval): Expansion of arguments to export/unexport was + ignoring all arguments after the first one. Change the algorithm + to expand the whole line once, then parse the results. + +2002-09-17 Paul D. Smith + + Fix Bug #940 (plus another bug I found while looking at this): + + * read.c (record_target_var): enter_file() will add a new entry if + it's a double-colon target: we don't want to do that in this + situation. Invoke lookup_file() and only enter_file() if it does + not already exist. If the file we get back is a double-colon then + add this variable to the "root" double-colon target. + + * variable.c (initialize_file_variables): If this file is a + double-colon target but is not the "root" target, then initialize + the root and make the root's variable list the parent of our + variable list. + +2002-09-13 Paul D. Smith + + * doc/make.texi (MAKE Variable): Add some indexing for "+". + + * hash.c (round_up_2): Get rid of a warning. + +2002-09-12 Paul D. Smith + + * Makefile.am (loadavg_SOURCES, loadavg.c): Tiptoe around automake + so it doesn't complain about getloadavg.c. + + * commands.c (set_file_variables): Make sure we always alloca() at + least 1 character for the value of $? (for '\0'). + +2002-09-11 Paul D. Smith + + * hash.h (STRING_COMPARE, ISTRING_COMPARE, STRING_N_COMPARE): Fix + macro to use RESULT instead of the incorrect _RESULT_. + + * make.h (HAVE_BROKEN_RESTART): Add prototypes for atomic_stat() + and atomic_readdir(). We need to #include dirent.h to get this to + work. + * misc.c (atomic_readdir): Fix typos. + +2002-09-10 Paul D. Smith + + * read.c (eval): Expand variable lists given to export and + unexport, so that "export $(LIST_OF_VARIABLES)" (etc.) works. + (conditional_line): Ditto for "ifdef". Fixes bug #103. + + * doc/make.texi (Variables/Recursion): Document this. + (Conditional Syntax): And here. + +2002-09-09 Paul D. Smith + + * configure.in: Check for memmove(). + +2002-09-07 Paul D. Smith + + * configure.in (HAVE_BROKEN_RESTART): Define this on PTX systems; + Michael Sterrett reports that while it has + SA_RESTART, it does not work properly. + + * misc.c (atomic_stat): If HAVE_BROKEN_RESTART, create a function + that invokes stat() and loops to do it again if it returns EINTR. + (atomic_readdir): Ditto, with readdir(). + + * make.h (stat, readdir): If HAVE_BROKEN_RESTART, alias stat() + and readdir() to atomic_stat() and atomic_readdir(). + +2002-09-04 Paul D. Smith + + * implicit.c (pattern_search): Daniel + reports that GNU make sometimes doesn't recognize that targets can + be made, when directories can be created as prerequisites. He + reports that changing the order of predicates in the DEP->changed + flag test so that lookup_file() is always performed, solves this + problem. + +2002-08-08 Paul D. Smith + + * configure.in: Require a newer version of gettext. + + * misc.c (perror_with_name): Translate the format string (for + right-to-left language support). + (pfatal_with_name): Ditto. + + * main.c: Create a static array of strings to store the usage + text. This is done to facilitate translations. + (struct command_switch): Remove argdesc and description fields. + (switches): Remove values for obsolete fields. + (print_usage): Print each element of the usage array. + + * hash.c: Change function definitions to be K&R style. + +2002-08-02 Paul D. Smith + + * NEWS: Remove the mention of .TARGETS; we aren't going to publish + this one because it's too hard to get right. We'll look at it for + a future release. + * main.c (main): Don't create the .TARGETS variable. + * variable.c (handle_special_var): Don't handle .TARGETS. + +2002-08-01 Paul D. Smith + + * main.c (switches): Add a new option, -B (--always-make). If + specified, make will rebuild all targets that it encounters even + if they don't appear to be out of date. + (always_make_flag): New flag. + * make.h: Extern always_make_flag. + * remake.c (update_file_1): Check always_make_flag; if it's set we + will always rebuild any target we can, even if none of its + prerequisites are newer. + * NEWS: Mention it. + + * doc/make.texi (Shell Function): Make it clear that make + variables marked as "export" are not passed to instances of the + shell function. + + Add new introspection variable .VARIABLES and .TARGETS. + + * variable.c (handle_special_var): New function. If the variable + reference passed in is "special" (.VARIABLES or .TARGETS), + calculate the new value if necessary. .VARIABLES is handled here: + walk through the hash of defined variables and construct a value + which is a list of the names. .TARGETS is handled by + build_target_list(). + (lookup_variable): Invoke handle_special_var(). + * file.c (build_target_list): Walk through the hask of known files + and construct a list of the names of all the ones marked as + targets. + * main.c (main): Initialize them to empty (and as simple variables). + * doc/make.texi (Special Variables): Document them. + * NEWS: Mention them. + + * variable.h (struct variable): Add a new flag "exportable" which + is true if the variable name is valid for export. + * variable.c (define_variable_in_set): Set "exportable" when a new + variable is defined. + (target_environment): Use the "exportable" flag instead of + re-checking the name here... an efficiency improvement. + +2002-07-31 Paul D. Smith + + * config.h-vms.template: Updates to build on VMS. Thanks to + Brian_Benning@aksteel.com for helping verify the build. + * makefile.com: Build the new hash.c file. + * hash.h: Use strcpmi(), not stricmp(), in the + HAVE_CASE_INSENSITIVE_FS case. + +2002-07-30 Paul D. Smith + + * hash.h (ISTRING_COMPARE, return_ISTRING_COMPARE): Add missing + backslashes to the HAVE_CASE_INSENSITIVE_FS case. + Reported by . + +2002-07-10 Paul D. Smith + + * variable.c (pop_variable_scope): Remove variable made unused by + new hash infrastructure. + * read.c (dep_hash_cmp): Rewrite this to handle ignore_mtime + comparisons as well as name comparisons. + * variable.h: Add a prototype for new hash_init_function_table(). + * file.c (lookup_file): Remove variables made unused by new hash + infrastructure. + * dir.c (directory_contents_hash_2): Missing return of hash value. + (dir_contents_file_exists_p): Remove variables made unused by new + hash infrastructure. + + + Installed Greg McGary's integration of the hash functions from the + GNU id-utils package: + +2002-07-10 Greg McGary + + * scripts/functions/filter-out: Add literals to to the + pattern space in order to add complexity, and trigger + use of an internal hash table. Fix documentation strings. + * scripts/targets/INTERMEDIATE: Reverse order of files + passed to expected `rm' command. + +2002-07-10 Greg McGary + + * Makefile.am (SRCS): Add hash.c (noinst_HEADERS): Add hash.h + * hash.c: New file, taken from id-utils. + * hash.h: New file, taken from id-utils. + + * make.h (HASH, HASHI): Remove macros. + (find_char_unquote): Change arglist in decl. + (hash_init_directories): New function decl. + * variable.h (hash.h): New #include. + (MAKELEVEL_NAME, MAKELEVEL_LENGTH): New constants. + * filedef.h (hash.h): New #include. + (struct file) [next]: Remove member. + (file_hash_enter): Remove function decl. + (init_hash_files): New function decl. + + * ar.c (ar_name): Delay call to strlen until needed. + * main.c (initialize_global_hash_tables): New function. + (main): Call it. Use MAKELEVEL_NAME & MAKELEVEL_LENGTH. + * misc.c (remove_comments): Pass char constants to find_char_unquote. + * remake.c (notice_finished_file): Update last_mtime on `prev' chain. + + * dir.c (hash.h): New #include. + (struct directory_contents) [next, files]: Remove members. + [ctime]: Add member for VMS. [dirfiles]: Add hash-table member. + (directory_contents_hash_1, directory_contents_hash_2, + directory_contents_hash_cmp): New functions. + (directories_contents): Change type to `struct hash_table'. + (struct directory) [next]: Remove member. + (directory_hash_1, directory_hash_2, directory_hash_cmp): New funcs. + (directory): Change type to `struct hash_table'. + (struct dirfile) [next]: Remove member. + [length]: Add member. [impossible]: widen type to fill alignment gap. + (dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp): New functions. + (find_directory): Use new hash table package. + (dir_contents_file_exists_p): Likewise. + (file_impossible): Likewise. + (file_impossible_p): Likewise. + (print_dir_data_base): Likewise. + (open_dirstream): Likewise. + (read_dirstream): Likewise. + (hash_init_directories): New function. + + * file.c (hash.h): New #include. + (file_hash_1, file_hash_2, file_hash_cmp): New functions. + (files): Change type to `struct hash_table'. + (lookup_file): Use new hash table package. + (enter_file): Likewise. + (remove_intermediates): Likewise. + (snap_deps): Likewise. + (print_file_data_base): Likewise. + + * function.c + (function_table_entry_hash_1, function_table_entry_hash_2, + function_table_entry_hash_cmp): New functions. + (lookup_function): Remove `table' argument. + Use new hash table package. + (struct a_word) [chain, length]: New members. + (a_word_hash_1, a_word_hash_2, a_word_hash_cmp): New functions. + (struct a_pattern): New struct. + (func_filter_filterout): Pass through patterns noting boundaries + and '%', if present. Note a_word length. Use a hash table if + arglists are large enough to justify cost. + (function_table_init): Renamed from function_table. + (function_table): Declare as `struct hash_table'. + (FUNCTION_TABLE_ENTRIES): New constant. + (hash_init_function_table): New function. + + * read.c (hash.h): New #include. + (read_makefile): Pass char constants to find_char_unquote. + (dep_hash_1, dep_hash_2, dep_hash_cmp): New functions. + (uniquize_deps): Use hash table to efficiently identify duplicates. + (find_char_unquote): Accept two char-constant stop chars, rather + than a string constant, avoiding zillions of calls to strchr. + Tighten inner search loops to test only for desired delimiters. + + * variable.c (variable_hash_1, variable_hash_2, + variable_hash_cmp): New functions. + (variable_table): Declare as `struct hash_table'. + (global_variable_set): Remove initialization. + (init_hash_global_variable_set): New function. + (define_variable_in_set): Use new hash table package. + (lookup_variable): Likewise. + (lookup_variable_in_set): Likewise. + (initialize_file_variables): Likewise. + (pop_variable_scope): Likewise. + (create_new_variable_set): Likewise. + (merge_variable_sets): Likewise. + (define_automatic_variables): Likewise. + (target_environment): Likewise. + (print_variable_set): Likewise. + +2002-07-10 Paul D. Smith + + Implement the SysV make syntax $$@, $$(@D), and $$(@F) in the + prerequisite list. A real SysV make will expand the entire + prerequisites list _twice_: we don't do that as it's a big + backward-compatibility problem. We only replace those specific + variables. + + * read.c (record_files): Replace any $@, $(@D), and $(@F) variable + references left in the list of prerequisites. Check for .POSIX as + we record targets, so we can disable non-POSIX behavior while + reading makefiles as well as running them. + (eval): Check the prerequisite list to see if we have anything + that looks like a SysV prerequisite variable reference. + +2002-07-09 Paul D. Smith + + * doc/make.texi (Prerequisite Types): Add a new section describing + order-only prerequisites. + + * read.c (uniquize_deps): If we have the same file as both a + normal and order-only prereq, get rid of the order-only prereq, + since the normal one supersedes it. + +2002-07-08 Paul D. Smith + + * AUTHORS: Added Greg McGary to the AUTHORS file. + * NEWS: Blurbed order-only prerequisites. + * file.c (print_file): Show order-only deps properly when printing + the database. + + * maintMakefile: Add "update" targets for wget'ing the latest + versions of various external files. Taken from Makefile.maint in + autoconf, etc. + + * dosbuild.bat: Somehow we got _double_ ^M's. Remove them. + Reported by Eli Zaretskii . + +2002-07-07 Paul D. Smith + + * po/*.po: Remove. We'll use wget to retrieve them at release + time. + + * variable.c (do_variable_definition) [W32]: On W32 using cmd + rather than a shell you get an exception. Make sure we look up + the variable. Patch provided by Eli Zaretskii . + + * remake.c (notice_finished_file): Fix handling of -t flag. + Patch provided by Henning Makholm . + + * implicit.c (pattern_search): Some systems apparently run short + of stack space, and using alloca() in this function caused an + overrun. I modified it to use xmalloc() on the two variables + which seemed like they might get large. Fixes Bug #476. + + * main.c (print_version): Update copyright notice to conform with + GNU standards. + (print_usage): Update help output. + + * function.c (func_eval): Create a new make function, $(eval + ...). Expand the arguments, put them into a buffer, then invoke + eval_buffer() on the resulting string. + (func_quote): Create a new function, $(quote VARNAME). Inserts + the value of the variable VARNAME without expanding it any + further. + + * read.c (struct ebuffer): Change the linebuffer structure to an + "eval buffer", which can be either a file or a buffer. + (eval_makefile): Move the code in the old read_makefile() which + located a makefile into here: create a struct ebuffer with that + information. Have it invoke the new function eval() with that + ebuffer. + (eval_buffer): Create a new function that creates a struct ebuffer + that holds a string buffer instead of a file. Have it invoke + eval() with that ebuffer. + (eval): New function that contains the guts of the old + read_makefile() function: this function parses makefiles. Obtains + data to parse from the provided ebuffer. Some modifications to + make the flow of the function cleaner and clearer. Still could + use some work here... + (do_define): Takes a struct ebuffer instead of a FILE*. Read the + contents of the define/endef variable from the ebuffer. + (readstring): Read the next line from a string-style ebuffer. + (readline): Read the next line from an ebuffer. If it's a string + ebuffer, invoke readstring(). If it's a FILE* ebuffer, read it + from the file. + + * dep.h (eval_buffer): Prototype eval_buffer(); + + * variable.c (do_variable_definition): Make sure that all + non-target-specific variables are registered in the global set. + If we're invoked from an $(eval ...) we might be inside a $(call + ...) or other function which has pushed a variable scope; we still + want to define our variables from evaluated makefile code in the + global scope. + +2002-07-03 Greg McGary + + * dep.h (struct dep) [ignore_mtime]: New member. + [changed]: convert to a bitfield. + * implicit.c (pattern_search): Zero ignore_mtime. + * main.c (main, handle_non_switch_argument): Likewise. + * rule.c (convert_suffix_rule): Likewise. + * read.c (read_all_makefiles, read_makefile, multi_glob): Likewise. + (read_makefile): Parse '|' in prerequisite list. + (uniquize_deps): Consider ignore_mtime when comparing deps. + * remake.c (update_file_1, check_dep): Don't force remake for + dependencies that have d->ignore_mtime. + * commands.c (FILE_LIST_SEPARATOR): New constant. + (set_file_variables): Don't include a + prerequisite in $+, $^ or $? if d->ignore_mtime. + Define $|. + +2002-06-18 Paul D. Smith + + * make.texinfo: Updates for next revision. New date/rev/etc. + Recreate all Info menus. Change license on the manual to the GNU + Free Documentation License. A number of typos. + (Variables Simplify): Don't use "-" before it's defined. + (Automatic Prerequisites): Rewrite the target example to work + properly if the compile fails. Remove incorrect comments about + how "set -e" behaves. + (Text Functions): Move the "word", "wordlist", "words", and + "firstword" functions here, from "File Name Functions". + * make-stds.texi: Update from latest GNU version. + * fdl.texi: (created) Import the latest GNU version. + +2002-06-06 Paul D. Smith + + * variable.c (do_variable_definition): New function: extract the + part of try_variable_definition() that actually sets the value + into a separate function. + (try_variable_definition): Call do_variable_definition() after + parsing the variable definition string. + (define_variable_in_set): Make the name argument const. + + * variable.h (enum variable_flavor): Make public. + (do_variable_definition): Create prototype. + + * read.c (read_all_makefiles): Create a new built-in variable, + MAKEFILE_LIST. + (read_makefile): Add each makefile read in to this variable value. + +2002-05-18 Eli Zaretskii + + * Makefile.DOS.template: Tweak according to changes in the + distribution. Add back the dependencies of *.o files. + + * configh.dos.template: Synchronize with config.h.in. + +2002-05-09 Paul D. Smith + + * file.c (file_timestamp_now): Use K&R function declaration. + + * getloadavg.c (getloadavg): Merge setlocale() fix from sh-utils + getloadavg.c. Autoconf thinks QNX is SVR4-like, but it isn't, so + #undef it. Remove predefined setup of NLIST_STRUCT. Decide + whether to include nlist.h based on HAVE_NLIST_H. Change obsolete + NLIST_NAME_UNION to new HAVE_STRUCT_NLIST_N_UN_N_NAME. + * configure.in (NLIST_STRUCT): Define this if we have nlist.h and + nlist.n_name is a pointer rather than an array. + + * acinclude.m4 (make_FUNC_SETVBUF_REVERSED): Grab the latest + version of AC_FUNC_SETVBUF_REVERSED from autoconf CVS. + * configure.in: Use it instead of the old version. + + * main.c (main): Prefer setvbuf() to setlinebuf(). + +2002-05-08 Paul D. Smith + + * Makefile.am (make_LDADD): Add GETLOADAVG_LIBS. + (loadavg_LDADD): Ditto. + +2002-04-29 Paul D. Smith + + * expand.c (recursively_expand_for_file): Rename + recursively_expand() to recursively_expand_for_file() and provide + an extra argument, struct file. If the argument is provided, set + the variable scope to that of the file before expanding. + * variable.h (recursively_expand): Make this a macro that invokes + recursively_expand_for_file() with a NULL file pointer. + * variable.c (target_environment): Call the renamed function and + provide the current file context. + Fixes Debian bug #144306. + +2002-04-28 Paul D. Smith + + Allow $(call ...) user-defined variables to be self-referencing + without throwing an error. Allows implementation of transitive + closures, among other possibly useful things. + Requested by: Philip Guenther + + * variable.h (struct variable): Add a new field: exp_count, and + new macros to hold its size and maximum value. + (warn_undefined): Make this a macro. + * variable.c (define_variable_in_set): Initialize it. + * expand.c (recursively_expand): If we detect recursive expansion + of a variable, check the exp_count field. If it's greater than 0 + allow the recursion and decrement the count. + (warn_undefined): Remove this (now a macro in variable.h). + * function.c (func_call): Before we expand the user-defined + function, modify its exp_count field to contain the maximum + number of recursive calls we'll allow. After the call, reset it + to 0. + +2002-04-21 Paul D. Smith + + Modified to use latest autoconf (2.53), automake (1.6.1), and + gettext (0.11.1). We're using gettext's new "external" support, + to avoid including libintl source with GNU make. + + * README.cvs: New file. Explain how to build GNU make from CVS. + + * configure.in: Modify checking for the system glob library. + Use AC_EGREP_CPP instead of AC_TRY_CPP. Remove the setting of + GLOBDIR (we will always put "glob" in SUBDIRS, so automake + etc. will manage it correctly). Set an automake conditional + USE_LOCAL_GLOB to decide whether to compile the glob library. + + * getloadavg.c (main): Include make.h in the "TEST" program to + avoid warnings. + + * Makefile.am: Remove special rules for loadavg. Replace them + with Automake capabilities for building extra programs. + + * signame.c: This file does nothing if the system provide + strsignal(). If not, it implements strsignal(). If the system + doesn't define sys_siglist, then we make our own; otherwise we use + the system version. + * signame.h: Removed. + + * main.c (main): No need to invoke signame_init(). Update copyright. + + * ABOUT-NLS: Removed. + * gettext.c: Removed. + * gettext.h: Get a simplified copy from the gettext package. + * po/*: Created. + * i18n/*.po: Moved to po/. + * i18n/: Removed. + + * config/*: Created. Contains package configuration helper files. + * config.guess, config.sub: Moved to config directory. + + * configure.in (AC_CONFIG_FILES): Add po/Makefile.in, config/Makefile. + Rework to use new-style autoconf features. Use the "external" + mode for gettext. Make the build.sh config file conditional on + whether build.sh.in exists, to avoid autoconf errors. + * acinclude.m4: Removed almost all macros as being obsolete. + Rewrote remaining macros to use AC_DEFINE. + * acconfig.h: Removed. + + * Makefile.am (EXTRA_DIST): Add config/config.rpath. Use a + conditional to handle customs support. Remove special handling + for i18n features. + +2002-04-20 Paul D. Smith + + * function.c (func_call): Don't mark the argument variables $1, + etc. as recursive. They've already been fully expanded so + there's no need to do it again, and doing so strips escaped $'s. + Reported by Sebastian Glita . + + * remake.c (notice_finished_file): Walk through double-colon + entries via the prev field, not the next field! + Reported by Greg McGary . + + * main.c (main): If the user specifies -q and asks for a specific + target which is a makefile, we got an assert. In that case it + turns out we should continue normally instead. + + * i18n/de.po, i18n/fr.po: Installed an updated translation. + + * i18n/he.po: Installed a new translation. + +2002-01-07 Paul D. Smith + + * i18n/es.po, i18n/ru.po: Installed an updated translation. + +2001-12-04 Paul D. Smith + + * i18n/ja.po: Installed an updated translation. + +2001-09-06 Paul Eggert + + * configure.in (AC_CHECK_HEADERS): Add sys/resource.h. + (AC_CHECK_FUNCS): Add getrlimit, setrlimit. + + * main.c: Include if it, getrlimit, and setrlimit + are available. + (main): Get rid of any avoidable limit on stack size. + +2001-09-04 Paul D. Smith + + * i18n/da.po: Installed an updated translation. + +2001-08-03 Paul D. Smith + + * i18n/fr.po: Installed an updated translation. + Resolves Debian bug #106720. + +2001-06-13 Paul D. Smith + + * i18n/da.po, configure.in (ALL_LINGUAS): Installed a new + translation. + +2001-06-11 Paul D. Smith + + * i18n/ko.po: Installed a new translation. + +2001-05-06 Paul D. Smith + + Modify the EINTR handling. + + * job.c (new_job): Reorganize the jobserver algorithm. Reorder + the way in which we manage the file descriptor/signal handler race + trap to be more efficient. + +2001-05-06 Paul Eggert + + Restart almost all system calls that are interrupted, instead + of worrying about EINTR. The lone exception is the read() for + job tokens. + + * configure.in (HAVE_SA_RESTART): New macro. + (MAKE_JOBSERVER): Define to 1 only if HAVE_SA_RESTART. + * main.c (main): Use SA_RESTART instead of the old, + nonstandard SA_INTERRUPT. + + * configure.in (AC_CHECK_FUNCS): Add bsd_signal. + * main.c (bsd_signal): New function or macro, + if the implementation doesn't supply it. + (The bsd_signal function will be in POSIX 1003.1-200x.) + (HANDLESIG): Remove. + (main, FATAL_SIG): Use bsd_signal instead of signal or HANDLESIG. + + * make.h (EINTR_SET): Remove. + (SA_RESTART): New macro. + + * arscan.c (ar_member_touch): Don't worry about EINTR. + * function.c (func_shell): Likewise. + * job.c (reap_children, free_child, new_job): Likewise. + * main.c (main): Likewise. + * remake.c (touch_file, name_mtime): Likewise. + + * arscan.c (ar_member_touch): Fix bug uncovered by EINTR removal; + if fstat failed with errno!=EINTR, the error was ignored. + + * job.c (set_child_handler_action_flags): New function. + (new_job): Use it to temporarily clear the SIGCHLD action flags + while reading the token. + +2001-05-02 Paul D. Smith + + * job.c (start_job_command): Don't add define/endef per-line flags + to the top-level flags setting. + +2001-04-03 Paul D. Smith + + * arscan.c (VMS_get_member_info,ar_scan) [VMS]: VMS sets the low + bit on error, so check for odd return values, not non-0 return + values. + (VMS_get_member_info): Calculate the timezone differences correctly. + Reported by John Fowler . + + +2001-03-14 Paul D. Smith + + * variable.c (lookup_variable) [VMS]: Null-terminate the variable + value before invoking define_variable(). + Reported by John Fowler . + +2001-02-07 Paul D. Smith + + * read.c (record_target_var): If we reset the variable due to a + command-line variable setting overriding it, turn off the "append" + flag. + +2001-01-17 Paul D. Smith + + * variable.c (lookup_variable) [VMS]: When getting values from the + environment, allocate enough space for the _value_ plus escapes, + not enough space for the name plus escapes :-/. + Reported by John Fowler . + + * remake.c (f_mtime): Removed the "***" prefix from the mod time + warnings that make generates, so it doesn't look like an error. + Reported by Karl Berry . + + + Fix for PR/2020: Rework appended target-specific variables. I'm + fairly confident this algorithm is finally correct. + + * expand.c (allocated_variable_append): Rewrite. Instead of + expanding each appended variable then adding all the expanded + strings together, we append all the unexpanded values going up + through the variable set contexts, then expand the final result. + This behaves just like non-target-specific appended variable + values, while the old way didn't in various corner cases. + (variable_append): New function: recursively append the unexpanded + value of a variable, walking from the outermost variable scope to + the innermost. + * variable.c (lookup_variable): Remove the code that looked up the + variable set list if the found variable was "append". We don't + need this anymore. + (lookup_variable_in_set): Make this non-static so we can use it + elsewhere. + (try_variable_definition): Use lookup_variable_in_set() rather + than faking out current_variable_set_list by hand (cleanup). + * variable.h: Add a prototype for the now non-static + lookup_variable_in_set(). + +2000-11-17 Paul D. Smith + + * remake.c (f_mtime) [WINDOWS32]: On various advice, I changed the + WINDOWS32 port to assume timestamps can be up to 3 seconds away + before throwing a fit. + +2000-11-17 Paul D. Smith + + * read.c (readline): CRLF calculations had a hole, if you hit the + buffer grow scenario just right. Reworked the algorithm to avoid + the need for len or lastlen at all. Problem description with + sample code chages provided by Chris Faylor . + +2000-10-24 Paul D. Smith + + * gettext.c (SWAP): Declare this with the prototype, otherwise + some systems don't work (non-32-bit? Reported for Cray T3E). + Reported by Thorstein Thorsteinsson . + +2000-10-05 Paul D. Smith + + * acinclude.m4 (AM_LC_MESSAGES): Remove undefined macro + AM_LC_MESSAGES; it doesn't seem to do anything anyway?? + + * i18n/gl.po, configure.in (ALL_LINGUAS): New Galician translation. + +2000-09-22 Paul D. Smith + + * gettext.c: Don't #define _GETTEXT_H here; we only include some + parts of the real gettext.h here, and we expect to really include + the real gettext.h later. If we keep this #define, it's ignored. + +2000-09-21 Paul D. Smith + + * main.c (log_working_directory): Rework the text to use complete + sentences, to make life simpler for the translators. + +2000-08-29 Paul D. Smith + + * file.c (remove_intermediates): Print a debug message before we + remove intermediate files, so the user (if she uses -d) knows + what's going on. + +2000-08-21 Paul D. Smith + + * variable.c (try_variable_definition): Change how we handle + target-specific append variable defns: instead of just setting the + value, expand it as an append _but_ only within the current + target's context. Otherwise we lose all but the last value if the + variable is appended more than once within the current target + context. Fixes PR/1831. + +2000-08-16 Paul D. Smith + + * function.c (func_shell): Nul-terminate the buffer before + printing an exec error message (just in case it's not!). + Fixes PR/1860, reported by Joey Hess . + +2000-07-25 Paul D. Smith + + * job.c (construct_command_argv_internal): Add "~" to the list of + sh_chars[] which disallow optimizing out the shell call. + +2000-07-23 Paul Eggert + + * NEWS, make.texinfo: Document .LOW_RESOLUTION_TIME, which + supersedes --disable-nsec-timestamps. + * make.texinfo: Consistently use "time stamp" instead of "timestamp". + * README: Remove --disable-nsec-timestamps. + + * filedef.h (struct file.low_resolution_time): New member. + * file.c (snap_deps): Add support for .LOW_RESOLUTION_TIME. + * remake.c (update_file_1): + Avoid spurious rebuilds due to low resolution time stamps, + generalizing the earlier code that applied only to archive members. + (f_mtime): Archive members always have low resolution time stamps. + + * configure.in: Remove --disable-nsec-timestamps, as this has + been superseded by .LOW_RESOLUTION_TIME. + +2000-07-23 Paul Eggert + + * configure.in (enable_nsec_timestamps): Renamed from + make_cv_nsec_timestamps, since enable/disable options + shouldn't be cached. + +2000-07-23 Bruno Haible + and Paul Eggert + + * file.c (file_timestamp_now): + Use preprocessor-time check for FILE_TIMESTAMP_HI_RES + so that clock_gettime is not linked unless needed. + + * filedef.h (FILE_TIMESTAMP_HI_RES): + Remove definition; "configure" now does this. + + * configure.in (jm_AC_TYPE_UINTMAX_T): Move up, + to before high resolution file timestamp check, + since that check now uses uintmax_t. + (FILE_TIMESTAMP_HI_RES): Define to nonzero if the code should use + high resolution file timestamps. + (HAVE_CLOCK_GETTIME): Do not define if !FILE_TIMESTAMP_HI_RES, + so that we don't link in clock_gettime unnecessarily. + +2000-07-17 Paul D. Smith + + * i18n/ja.po: New version of the translation file. + +2000-07-07 Paul D. Smith + + * remake.c (f_mtime): If NO_FLOAT is defined, don't bother with + the offset calculation. + (name_mtime): Replace EINTR test with EINTR_SET macro. + +2000-07-07 Paul Eggert + + Fix for PR/1811: + + * remake.c (update_file_1): + Avoid spurious rebuilds of archive members due to their + timestamp resolution being only one second. + (f_mtime): Avoid spurious warnings of timestamps in the future due to + the clock's resolution being lower than file timestamps'. + When warning about future timestamps, report only the discrepancy, + not the absolute value of the timestamp and the current time. + + * file.c (file_timestamp_now): New arg RESOLUTION. + * filedef.h (file_timestamp_now): Likewise. + (FILE_TIMESTAMP_NS): Now returns int. All uses changed. + +2000-07-05 Paul D. Smith + + * variable.c (lookup_variable) [VMS]: Remove vestigial references + to listp. Fixes PR/1793. + +2000-06-26 Paul Eggert + + * Makefile.am (MAINTAINERCLEANFILES): New macro, with stamp-pot in it. + + * dir.c (vms_hash): Ensure ctype macro args are nonnegative. + + * remake.c (f_mtime): Remove unused var memtime. + +2000-06-25 Martin Buchholz + + * make.texinfo, NEWS, TODO.private: Minor spelling corrections. + Ran spell-check on make.texinfo. + +2000-06-23 Paul D. Smith + + * main.c (main): Replace EXIT_SUCCESS, EXIT_FAILURE, and + EXIT_TROUBLE with MAKE_SUCCESS, MAKE_FAILURE, and MAKE_TROUBLE. + * make.h: Define these macros. + + * Version 3.79.1 released. + + * configure.in: Add a new option, --disable-nsec-timestamps, to + avoid using sub-second timestamps on systems that support it. It + can lead to problems, e.g. if your makefile relies on "cp -p". + * README.template: Document the issue with "cp -p". + + * config.guess, config.sub: Updated. + + + +See ChangeLog.2, available in the Git repository at: + + http://git.savannah.gnu.org/cgit/make.git/tree/ + +for earlier changes. + + +Copyright (C) 2000-2013 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . diff --git a/src/kmk/INSTALL b/src/kmk/INSTALL new file mode 100644 index 0000000..095b1eb --- /dev/null +++ b/src/kmk/INSTALL @@ -0,0 +1,231 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004 Free +Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PREFIX', the package will +use PREFIX as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +will cause the specified gcc to be used as the C compiler (unless it is +overridden in the site shell script). + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/src/kmk/Makefile.DOS.template b/src/kmk/Makefile.DOS.template new file mode 100644 index 0000000..47d83eb --- /dev/null +++ b/src/kmk/Makefile.DOS.template @@ -0,0 +1,587 @@ +# -*-Makefile-*- template for DJGPP +# Makefile.in generated automatically by automake 1.2 from Makefile.am +# +# Copyright (C) 1994-2016 Free Software Foundation, Inc. +# This file is part of GNU Make. +# +# GNU Make is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +SHELL = /bin/sh + +srcdir = . +VPATH = $(srcdir) +# $DJDIR is defined automatically by DJGPP to point +# to the root of the DJGPP installation tree. +prefix = /dev/env/DJDIR +exec_prefix = ${prefix} + +bindir = /bin +datadir = /share +libdir = /lib +infodir = /info +mandir = /man +includedir = /include +oldincludedir = c:/djgpp/include + +DESTDIR = /dev/env/DJDIR + +pkgdatadir = $(datadir)/make +pkglibdir = $(libdir)/make +pkgincludedir = $(includedir)/make +localedir = $(datadir)/locale + +INSTALL = ${exec_prefix}/bin/ginstall -c +INSTALL_PROGRAM = ${exec_prefix}/bin/ginstall -c +INSTALL_DATA = ${exec_prefix}/bin/ginstall -c -m 644 +INSTALL_SCRIPT = ${exec_prefix}/bin/ginstall -c +transform = s,x,x, + +# This will fail even if they don't have a Unix-like shell (stock DOS +# shell doesn't know about `false'). The only difference is that they +# get "Error -1" instead of "Error 1". +EXIT_FAIL = false + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +EXEEXT = .exe +OBJEXT = o + +AR = ar +AWK = gawk +CC = gcc +CPP = gcc -E +LIBOBJS = +MAKEINFO = ${exec_prefix}/bin/makeinfo +PACKAGE = make +PERL = perl +RANLIB = ranlib +REMOTE = stub +VERSION = %VERSION% + +AUTOMAKE_OPTIONS = 1.2 + +bin_PROGRAMS = %PROGRAMS%$(EXEEXT) + +make_SOURCES = %SOURCES% +# This should include the glob/ prefix +libglob_a_SOURCES = %GLOB_SOURCES% +make_LDADD = glob/libglob.a + +man_MANS = make.1 + +INCLUDES = -I$(srcdir)/glob -DLIBDIR=\"$(prefix)$(libdir)\" -DINCLUDEDIR=\"$(prefix)$(includedir)\" -DLOCALEDIR=\"$(prefix)$(localedir)\" + +BUILT_SOURCES = README build.sh-in + +EXTRA_DIST = $(BUILT_SOURCES) $(man_MANS) README.customs remote-cstms.c make-stds.texi texinfo.tex SCOPTIONS SMakefile Makefile.ami README.Amiga config.ami amiga.c amiga.h NMakefile README.DOS configh.dos configure.bat makefile.com README.W32 build_w32.bat config.h-W32 subproc.bat make.lnk config.h-vms makefile.vms README.VMS vmsdir.h vmsfunctions.c vmsify.c gmk-default.scm gmk-default.h + +SUBDIRS = glob doc +mkinstalldirs = ${exec_prefix}/bin/gmkdir -p +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = build.sh +PROGRAMS = $(bin_PROGRAMS) + +MAKE_HOST = i386-pc-msdosdjgpp + + +DEFS = -I. -I$(srcdir) -I. +CPPFLAGS = -DHAVE_CONFIG_H +LDFLAGS = +LIBS = +make_OBJECTS = %OBJECTS% +make_DEPENDENCIES = glob/libglob.a +make_LDFLAGS = +libglob_a_LIBADD = +libglob_a_OBJECTS = %GLOB_OBJECTS% +noinst_LIBRARIES = glob/libglob.a +CFLAGS = -O2 -g +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) +LINK = $(CC) $(CFLAGS) $(LDFLAGS) -o $@ +TEXI2DVI = texi2dvi +TEXINFO_TEX = $(srcdir)/config/texinfo.tex +INFO_DEPS = doc/make.info +DVIS = doc/make.dvi +TEXINFOS = doc/make.texi +noinst_TEXINFOS = doc/fdl.texi doc/make-stds.texi +man1dir = $(mandir)/man1 +MANS = $(man_MANS) + +NROFF = nroff +DIST_COMMON = README ABOUT-NLS AUTHORS COPYING ChangeLog INSTALL Makefile.am Makefile.in NEWS acconfig.h aclocal.m4 alloca.c build.sh-in config.h-in configure configure.ac getloadavg.c + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = gtar +GZIP = --best +SOURCES = $(make_SOURCES) +OBJECTS = $(make_OBJECTS) +HEADERS = $(wildcard $(srcdir)/*.h) + +default: all + +.SUFFIXES: +.SUFFIXES: .c .dvi .info .o .obj .ps .texi .tex .html + +mostlyclean-hdr: + +clean-hdr: + +distclean-hdr: + -rm -f config.h + +maintainer-clean-hdr: + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do if test -f $$p; then echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p | sed '$(transform)'`"; $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p | sed '$(transform)'`; else :; fi; done + +uninstall-binPROGRAMS: + $(NORMAL_UNINSTALL) + list='$(bin_PROGRAMS)'; for p in $$list; do rm -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`.exe; done + +.c.o: + $(COMPILE) -c $< + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) *$(EXEEXT) make.new core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c *_tab.c + +maintainer-clean-compile: + +make$(EXEEXT): $(make_OBJECTS) $(make_DEPENDENCIES) + @command.com /c if exist make del make + @command.com /c if exist make.exe del make.exe + $(LINK) $(make_LDFLAGS) $(make_OBJECTS) $(make_LDADD) $(LIBS) + +# Documentation + +make.info: make.texi +make.dvi: make.texi +make.ps: make.dvi make.texi +make.html: make.texi + + +DVIPS = dvips + +.texi.info: + @command.com /c if exist make.info* del make.info* + @command.com /c if exist make.i* del make.i* + $(MAKEINFO) -I$(srcdir) --no-split $< -o ./$@ + +.texi: + @command.com /c if exist make.info* del make.info* + @command.com /c if exist make.i* del make.i* + $(MAKEINFO) -I$(srcdir) --no-split $< -o ./$@ + +.texi.dvi: + TEXINPUTS="$(srcdir);$$TEXINPUTS" MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $< + +.dvi.ps: + $(DVIPS) $< -o $@ + +# Other documentation formats + +html: html-recursive + +.texi.html: + @command.com /c if exist make.html* del make.html* + $(MAKEINFO) --html -I$(srcdir) --no-split $< -o ./$@ + +install-info-am: $(INFO_DEPS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(infodir) + @for file in $(INFO_DEPS); do iifile=`echo $$file | sed "s|doc/||"`; d=$(srcdir); for ifile in `cd $$d && echo $$file`; do if test -f $$d/$$ifile; then echo " $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$iifile"; $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$iifile; else : ; fi; done; done + @$(POST_INSTALL) + @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then for file in $(INFO_DEPS); do iifile=`echo $$file | sed "s|doc/||"`; echo " install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$iifile"; install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$iifile || :; done; else : ; fi + +uninstall-info: + $(PRE_UNINSTALL) + @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then ii=yes; else ii=; fi; for file in $(INFO_DEPS); do test -z $ii || install-info --info-dir=$(DESTDIR)$(infodir) --remove $$file; done + $(NORMAL_UNINSTALL) + for file in $(INFO_DEPS); do (cd $(DESTDIR)$(infodir) && rm -f $$file); done + +dist-info: $(INFO_DEPS) + for base in $(INFO_DEPS); do d=$(srcdir); for file in `cd $$d && eval echo $$base*`; do test -f $(distdir)/$$file || ln $$d/$$file $(distdir)/$$file 2> /dev/null || cp -p $$d/$$file $(distdir)/$$file; done; done + +mostlyclean-aminfo: + -rm -f $(srcdir)/doc/make.aux $(srcdir)/doc/make.cp $(srcdir)/doc/make.cps $(srcdir)/doc/make.dvi \ + $(srcdir)/doc/make.fn $(srcdir)/doc/make.fns $(srcdir)/doc/make.ky $(srcdir)/doc/make.kys \ + $(srcdir)/doc/make.ps $(srcdir)/doc/make.log $(srcdir)/doc/make.pg $(srcdir)/doc/make.toc \ + $(srcdir)/doc/make.tp $(srcdir)/doc/make.tps $(srcdir)/doc/make.vr $(srcdir)/doc/make.vrs \ + $(srcdir)/doc/make.op $(srcdir)/doc/make.tr $(srcdir)/doc/make.cv $(srcdir)/doc/make.cn \ + $(srcdir)/doc/make.html + +clean-aminfo: + +distclean-aminfo: + +maintainer-clean-aminfo: + for i in $(INFO_DEPS); do rm -f $$i*; done + +install-man1: + $(mkinstalldirs) $(DESTDIR)$(man1dir) + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \ + done + +uninstall-man1: + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \ + rm -f $(DESTDIR)$(man1dir)/$$inst; \ + done +install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) install-man1 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) uninstall-man1 + +# Assume that the only thing to do in glob is to build libglob.a, +# but do a sanity check: if $SUBDIRS will ever have more than +# a single directory, yell bloody murder. +all-recursive: +ifeq ($(findstring glob, $(SUBDIRS)), glob) + @command.com /c if not exist glob\\nul md glob + @echo Making all in glob + $(MAKE) -C glob -f ../Makefile INCLUDES='-I$(srcdir) -I$(srcdir)/glob' DEFS='-I.. -I$(srcdir)' VPATH=$(srcdir)/glob libglob.a +endif + +$(SUBDIRS): + command.com /c md $@ + +libglob.a: $(libglob_a_OBJECTS) + command.com /c if exist libglob.a del libglob.a + $(AR) cru libglob.a $(libglob_a_OBJECTS) $(libglob_a_LIBADD) + $(RANLIB) libglob.a + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive check-recursive: +ifeq ($(words $(SUBDIRS)), 2) + @echo Making $(shell echo $@ | sed s/-recursive//) in glob + $(MAKE) -C glob -f ../Makefile $(shell echo $@ | sed s/-recursive//)-am + @echo Making $(shell echo $@ | sed s/-recursive//) in doc + $(MAKE) -C doc -f ../Makefile $(shell echo $@ | sed s/-recursive//)-am +else + @echo FATAL: There is more than two directory in "($(SUBDIRS))" + @$(EXIT_FAIL) +endif + +tags-in-glob: $(libglob_a_SOURCES) + etags $(addprefix $(srcdir)/,$^) -o ./glob/TAGS + +tags-recursive: +ifeq ($(words $(SUBDIRS)), 2) + $(MAKE) tags-in-glob +else + @echo FATAL: There is more than two directory in "($(SUBDIRS))" + @$(EXIT_FAIL) +endif + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) + mkid $(srcdir)/$(SOURCES) $(srcdir)/$(libglob_a_SOURCES) ./config.h $(HEADERS) + +TAGS: tags-recursive $(HEADERS) $(srcdir)/$(SOURCES) config.h $(TAGS_DEPENDENCIES) + etags -i ./glob/TAGS $(ETAGS_ARGS) $(srcdir)/$(SOURCES) ./config.h $(HEADERS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + rm -rf $(distdir) + GZIP=$(GZIP) $(TAR) zxf $(distdir).tar.gz + mkdir $(distdir)/=build + mkdir $(distdir)/=inst + dc_install_base=`cd $(distdir)/=inst && pwd`; cd $(distdir)/=build && ../configure --srcdir=.. --prefix=$$dc_install_base && $(MAKE) && $(MAKE) dvi && $(MAKE) check && $(MAKE) install && $(MAKE) installcheck && $(MAKE) dist + rm -rf $(distdir) + @echo "========================"; echo "$(distdir).tar.gz is ready for distribution"; echo "========================" +dist: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP) $(TAR) chozf $(distdir).tar.gz $(distdir) + rm -rf $(distdir) +dist-all: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP) $(TAR) chozf $(distdir).tar.gz $(distdir) + rm -rf $(distdir) +distdir: $(DISTFILES) + rm -rf $(distdir) + mkdir $(distdir) + -chmod 777 $(distdir) + @for file in $(DISTFILES); do d=$(srcdir); test -f $(distdir)/$$file || ln $$d/$$file $(distdir)/$$file 2> /dev/null || cp -p $$d/$$file $(distdir)/$$file; done; for subdir in $(SUBDIRS); do test -d $(distdir)/$$subdir || mkdir $(distdir)/$$subdir || exit 1; chmod 777 $(distdir)/$$subdir; (cd $$subdir && $(MAKE) top_distdir=../$(top_distdir)/$$subdir distdir=../$(distdir)/$$subdir distdir) || exit 1; done + $(MAKE) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-info + $(MAKE) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook + +info: info-recursive +info-recursive: +ifeq ($(findstring doc, $(SUBDIRS)), doc) + @command.com /c if not exist doc\\nul md doc + @echo Making all in doc + $(MAKE) -C doc -f ../Makefile VPATH=$(srcdir)/doc make.info +endif + +dvi: dvi-recursive +dvi-recursive: +ifeq ($(findstring doc, $(SUBDIRS)), doc) + @command.com /c if not exist doc\\nul md doc + @echo Making all in doc + $(MAKE) -C doc -f ../Makefile VPATH=$(srcdir)/doc make.dvi +endif + +ps: ps-recursive +ps-recursive: +ifeq ($(findstring doc, $(SUBDIRS)), doc) + @command.com /c if not exist doc\\nul md doc + @echo Making all in doc + $(MAKE) -C doc -f ../Makefile VPATH=$(srcdir)/doc make.ps +endif + +html-recursive: +ifeq ($(findstring doc, $(SUBDIRS)), doc) + @command.com /c if not exist doc\\nul md doc + @echo Making all in doc + $(MAKE) -C doc -f ../Makefile VPATH=$(srcdir)/doc make.html +endif + +check: all-am check-recursive check-local + @: +installcheck: installcheck-recursive +all-recursive-am: config.h + $(MAKE) all-recursive + +all-am: Makefile $(PROGRAMS) config.h info + +install-exec-am: install-binPROGRAMS + +install-data-am: install-info-am + +uninstall-am: uninstall-binPROGRAMS uninstall-info + +install-exec: install-exec-recursive install-exec-am + @$(NORMAL_INSTALL) + +install-data: install-data-recursive install-data-am + @$(NORMAL_INSTALL) + +install-recursive uninstall-recursive: + @: + +install: install-recursive install-exec-am install-data-am + @: + +uninstall: uninstall-recursive uninstall-am + +all: all-recursive-am all-am + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install +installdirs: installdirs-recursive + $(mkinstalldirs) $(bindir) $(infodir) + + +mostlyclean-generic: + -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(DISTCLEANFILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean-am: mostlyclean-hdr mostlyclean-binPROGRAMS mostlyclean-compile mostlyclean-aminfo mostlyclean-tags mostlyclean-generic + +clean-am: clean-hdr clean-binPROGRAMS clean-compile clean-aminfo clean-tags clean-generic mostlyclean-am + +distclean-am: distclean-hdr distclean-binPROGRAMS distclean-compile distclean-aminfo distclean-tags distclean-generic clean-am + +maintainer-clean-am: maintainer-clean-hdr maintainer-clean-binPROGRAMS maintainer-clean-compile maintainer-clean-aminfo maintainer-clean-tags maintainer-clean-generic distclean-am + +mostlyclean: mostlyclean-recursive mostlyclean-am + +clean: clean-noinstLIBRARIES clean-recursive clean-am + +distclean: distclean-recursive distclean-am + rm -f config.status + +maintainer-clean: maintainer-clean-recursive maintainer-clean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + rm -f config.status + +.PHONY: default mostlyclean-hdr distclean-hdr clean-hdr \ +maintainer-clean-hdr mostlyclean-binPROGRAMS distclean-binPROGRAMS \ +clean-binPROGRAMS maintainer-clean-binPROGRAMS uninstall-binPROGRAMS \ +install-binPROGRAMS mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-info-am uninstall-info \ +mostlyclean-aminfo distclean-aminfo clean-aminfo \ +maintainer-clean-aminfo install-data-recursive uninstall-data-recursive \ +install-exec-recursive uninstall-exec-recursive installdirs-recursive \ +uninstalldirs-recursive all-recursive check-recursive check-am \ +installcheck-recursive info-recursive dvi-recursive \ +mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir \ +mostlyclean-depend distclean-depend clean-depend \ +maintainer-clean-depend info dvi check-local installcheck \ +all-recursive-am all-am install-exec-am install-data-am uninstall-am \ +install-exec install-data install uninstall all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean \ +html + + +# --------------- Local DIST Section + +# Install the w32 subdirectory +# +dist-hook: + (cd $(srcdir); \ + w32=`find w32 -follow \( -name .git -prune \) -o -type f -print`; \ + tar chf - $$w32) \ + | (cd $(distdir); tar xfBp -) + +# --------------- Local CHECK Section + +# Note: check-loadavg is NOT a prerequisite of check-local, since +# there's no uptime utility, and the test it does doesn't make sense +# on MSDOS anyway. +check-local: check-shell check-regression + @banner=" Regression PASSED: GNU Make $(VERSION) ($(MAKE_HOST)) built with $(CC) "; \ + dashes=`echo "$$banner" | sed s/./=/g`; \ + echo; \ + echo "$$dashes"; \ + echo "$$banner"; \ + echo "$$dashes"; \ + echo + +.PHONY: check-loadavg check-shell check-regression + +# > check-shell +# +# check-shell is designed to fail if they don't have a Unixy shell +# installed. The test suite requires such a shell. +check-shell: + @echo If Make says Error -1, you do not have Unix-style shell installed + @foo=bar.exe : + +# > check-loadavg +# +loadavg: loadavg.c config.h + @rm -f loadavg + $(LINK) -DTEST $(make_LDFLAGS) loadavg.c $(LIBS) +# We copy getloadavg.c into a different file rather than compiling it +# directly because some compilers clobber getloadavg.o in the process. +loadavg.c: getloadavg.c + ln $(srcdir)/getloadavg.c loadavg.c || \ + cp $(srcdir)/getloadavg.c loadavg.c +check-loadavg: loadavg + @echo The system uptime program believes the load average to be: + -uptime + @echo The GNU load average checking code believes: + -./loadavg + +# > check-regression +# +# Look for the make test suite, and run it if found. Look in MAKE_TEST if +# specified, or else in the srcdir or the distdir, their parents, and _their_ +# parents. +# +check-regression: + @if test -f "$(srcdir)/tests/run_make_tests"; then \ + if $(PERL) -v >/dev/null 2>&1; then \ + case `cd $(srcdir); pwd` in `pwd`) : ;; \ + *) test -d tests || mkdir tests; \ + for f in run_make_tests run_make_tests.pl test_driver.pl scripts; do \ + rm -rf tests/$$f; cp -pr $(srcdir)/tests/$$f tests; \ + done ;; \ + esac; \ + echo "cd tests && $(PERL) ./run_make_tests.pl -make ../make.exe $(MAKETESTFLAGS)"; \ + cd tests && $(PERL) ./run_make_tests.pl -make ../make.exe $(MAKETESTFLAGS); \ + else \ + echo "Can't find a working Perl ($(PERL)); the test suite requires Perl."; \ + fi; \ + else \ + echo "Can't find the GNU Make test suite ($(srcdir)/tests)."; \ + fi + +# --------------- Maintainer's Section + +# Note this requires GNU make. Not to worry, since it will only be included +# in the Makefile if we're in the maintainer's environment. +#include $(srcdir)/maintMakefile + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: + +# --------------- DEPENDENCIES diff --git a/src/kmk/Makefile.am b/src/kmk/Makefile.am new file mode 100644 index 0000000..12cc103 --- /dev/null +++ b/src/kmk/Makefile.am @@ -0,0 +1,333 @@ +# This is a -*-Makefile-*-, or close enough +# +# Copyright (C) 1997-2016 Free Software Foundation, Inc. +# This file is part of GNU Make. +# +# GNU Make is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +AUTOMAKE_OPTIONS = dist-bzip2 silent-rules std-options +ACLOCAL_AMFLAGS = -I config + +MAKE_HOST = @MAKE_HOST@ + +# Only process if target is MS-Windows +if WINDOWSENV + MAYBE_W32 = w32 + W32INC = -I $(top_srcdir)/w32/include + W32LIB = -Lw32 -lw32 + ossrc = +else + ossrc = posixos.c +endif + +# we can safely drop doc and po when bootstrapping kmk. +# SUBDIRS = glob config po doc $(MAYBE_W32) +SUBDIRS = glob config $(MAYBE_W32) + +bin_PROGRAMS = kmk kmk_redirect +include_HEADERS = gnumake.h + +if USE_CUSTOMS + remote = remote-cstms.c +else + remote = remote-stub.c +endif + +kmk_SOURCES = ar.c arscan.c commands.c default.c dir.c expand.c file.c \ + function.c getopt.c getopt1.c guile.c implicit.c job.c load.c \ + loadapi.c main.c misc.c $(ossrc) output.c read.c remake.c \ + rule.c signame.c strcache.c variable.c version.c vpath.c \ + hash.c $(remote) \ + \ + expreval.c \ + incdep.c \ + strcache2.c \ + alloccache.c \ + kbuild.c \ + kbuild-object.c \ + electric.c \ + ../lib/md5.c \ + ../lib/kDep.c \ + ../lib/kbuild_version.c \ + ../lib/dos2unix.c \ + ../lib/maybe_con_fwrite.c \ + ../lib/version_compare.c \ + \ + kmkbuiltin.c \ + kmkbuiltin/append.c \ + kmkbuiltin/cat.c \ + kmkbuiltin/chmod.c \ + kmkbuiltin/cmp.c \ + kmkbuiltin/cmp_util.c \ + kmkbuiltin/cp.c \ + kmkbuiltin/cp_utils.c \ + kmkbuiltin/echo.c \ + kmkbuiltin/expr.c \ + kmkbuiltin/install.c \ + kmkbuiltin/kDepIDB.c \ + kmkbuiltin/kDepObj.c \ + kmkbuiltin/ln.c \ + kmkbuiltin/md5sum.c \ + kmkbuiltin/mkdir.c \ + kmkbuiltin/mv.c \ + kmkbuiltin/printf.c \ + kmkbuiltin/redirect.c \ + kmkbuiltin/rm.c \ + kmkbuiltin/rmdir.c \ + kmkbuiltin/sleep.c \ + kmkbuiltin/test.c \ + kmkbuiltin/touch.c \ + \ + kmkbuiltin/err.c \ + kmkbuiltin/getopt_r.c \ + kmkbuiltin/getopt1_r.c \ + kmkbuiltin/fts.c \ + kmkbuiltin/setmode.c \ + kmkbuiltin/strmode.c \ + kmkbuiltin/strlcpy.c \ + kmkbuiltin/osdep.c \ + kmkbuiltin/kbuild_protection.c \ + kmkbuiltin/common-env-and-cwd-opt.c + +kmk_redirect_SOURCES = kmkbuiltin/redirect.c \ + kmkbuiltin/common-env-and-cwd-opt.c \ + kmkbuiltin/err.c \ + ../lib/kbuild_version.c +kmk_redirect_CFLAGS = -UKMK -DKMK_BUILTIN_STANDALONE + +EXTRA_kmk_SOURCES = vmsjobs.c remote-stub.c remote-cstms.c + +noinst_HEADERS = commands.h dep.h filedef.h job.h makeint.h rule.h variable.h \ + debug.h getopt.h gettext.h hash.h output.h os.h + +#kmk_LDADD = @LIBOBJS@ @ALLOCA@ $(GLOBLIB) @GETLOADAVG_LIBS@ @LIBINTL@ +kmk_LDADD = @LIBOBJS@ @ALLOCA@ $(GLOBLIB) @GETLOADAVG_LIBS@ \ + $(GUILE_LIBS) +# Only process if target is MS-Windows +if WINDOWSENV + kmk_LDADD += $(W32LIB) +endif + +man_MANS = make.1 + +# org - DEFS = -DLOCALEDIR=\"$(localedir)\" -DLIBDIR=\"$(libdir)\" -DINCLUDEDIR=\"$(includedir)\" @DEFS@ +DEFS = \ + -DNO_ARCHIVES \ + -DEXPERIMENTAL \ + -DCONFIG_WITH_TOUPPER_TOLOWER \ + -DCONFIG_WITH_DEFINED \ + -DCONFIG_WITH_EXPLICIT_MULTITARGET \ + -DCONFIG_WITH_DOT_MUST_MAKE \ + -DCONFIG_WITH_PREPEND_ASSIGNMENT \ + -DCONFIG_WITH_LOCAL_VARIABLES \ + -DCONFIG_WITH_2ND_TARGET_EXPANSION \ + -DCONFIG_WITH_ALLOC_CACHES \ + -DCONFIG_WITH_STRCACHE2 \ + \ + -DKMK \ + -DKMK_HELPERS \ + -DCONFIG_NO_DEFAULT_SUFFIXES \ + -DCONFIG_NO_DEFAULT_PATTERN_RULES \ + -DCONFIG_NO_DEFAULT_TERMINAL_RULES \ + -DCONFIG_NO_DEFAULT_SUFFIX_RULES \ + -DCONFIG_NO_DEFAULT_VARIABLES \ + -DCONFIG_WITH_EXTENDED_NOTPARALLEL \ + -DCONFIG_WITH_INCLUDEDEP \ + -DCONFIG_WITHOUT_THREADS \ + -DCONFIG_WITH_VALUE_LENGTH \ + \ + -DCONFIG_WITH_ABSPATHEX \ + -DCONFIG_WITH_COMMANDS_FUNC \ + -DCONFIG_WITH_DATE \ + -DCONFIG_WITH_DEFINED_FUNCTIONS \ + -DCONFIG_WITH_EVALPLUS \ + -DCONFIG_WITH_FILE_SIZE \ + -DCONFIG_WITH_LOOP_FUNCTIONS \ + -DCONFIG_WITH_MATH \ + -DCONFIG_WITH_NANOTS \ + -DCONFIG_WITH_ROOT_FUNC \ + -DCONFIG_WITH_RSORT \ + -DCONFIG_WITH_STACK \ + -DCONFIG_WITH_STRING_FUNCTIONS \ + -DCONFIG_WITH_WHERE_FUNCTION \ + -DCONFIG_WITH_WHICH \ + -DCONFIG_WITH_XARGS \ + \ + -DCONFIG_WITH_COMPARE \ + -DCONFIG_WITH_SET_CONDITIONALS \ + -DCONFIG_WITH_IF_CONDITIONALS \ + -DCONFIG_WITH_PRINTF \ + -DCONFIG_WITH_MINIMAL_STATS \ + -DCONFIG_PRETTY_COMMAND_PRINTING \ + -DCONFIG_WITH_PRINT_STATS_SWITCH \ + -DCONFIG_WITH_PRINT_TIME_SWITCH \ + -DCONFIG_WITH_RDONLY_VARIABLE_VALUE \ + -DCONFIG_WITH_LAZY_DEPS_VARS \ + \ + -DKBUILD_TYPE=\"$(KBUILD_TYPE)\" \ + -DKBUILD_HOST=\"$(KBUILD_TARGET)\" \ + -DKBUILD_HOST_ARCH=\"$(KBUILD_TARGET_ARCH)\" \ + -DKBUILD_HOST_CPU=\"$(KBUILD_TARGET_CPU)\" \ + \ + -DKBUILD_SVN_REV=1 \ + -DKBUILD_VERSION_MAJOR=0 \ + -DKBUILD_VERSION_MINOR=1 \ + -DKBUILD_VERSION_PATCH=9998 \ + \ + -DCONFIG_WITH_KMK_BUILTIN \ + @DEFS@ + +AM_CPPFLAGS = $(GLOBINC) -I$(srcdir)/../lib -I$(srcdir)/../lib/kStuff/include +AM_CFLAGS = $(GUILE_CFLAGS) +# Only process if target is MS-Windows +if WINDOWSENV + AM_CPPFLAGS += $(W32INC) +endif + + +# Extra stuff to include in the distribution. + +EXTRA_DIST = ChangeLog README build.sh.in $(man_MANS) \ + README.customs README.OS2 \ + SCOPTIONS SMakefile \ + README.Amiga Makefile.ami config.ami make.lnk amiga.c amiga.h \ + README.DOS Makefile.DOS configure.bat dosbuild.bat configh.dos\ + README.W32 NMakefile config.h.W32 build_w32.bat subproc.bat \ + make_msvc_net2003.sln make_msvc_net2003.vcproj \ + README.VMS makefile.vms makefile.com config.h-vms \ + vmsdir.h vmsfunctions.c vmsify.c vms_exit.c vms_progname.c \ + vms_export_symbol.c vms_export_symbol_test.com \ + gmk-default.scm gmk-default.h + +# This is built during configure, but behind configure's back + +DISTCLEANFILES = build.sh + +# --------------- Internationalization Section + +localedir = $(datadir)/locale + +# --------------- Local INSTALL Section + +# If necessary, change the gid of the app and turn on the setgid flag. +# + +# Whether or not make needs to be installed setgid. +# The value should be either 'true' or 'false'. +# On many systems, the getloadavg function (used to implement the '-l' +# switch) will not work unless make is installed setgid kmem. +# +inst_setgid = @NEED_SETGID@ + +# Install make setgid to this group so it can get the load average. +# +inst_group = @KMEM_GROUP@ + +install-exec-local: + @if $(inst_setgid); then \ + app=$(DESTDIR)$(bindir)/`echo $(bin_PROGRAMS)|sed '$(transform)'`; \ + if chgrp $(inst_group) $$app && chmod g+s $$app; then \ + echo "chgrp $(inst_group) $$app && chmod g+s $$app"; \ + else \ + echo "$$app needs to be owned by group $(inst_group) and setgid;"; \ + echo "otherwise the '-l' option will probably not work."; \ + echo "You may need special privileges to complete the installation"; \ + echo "of $$app."; \ + fi; \ + else true; fi + +# --------------- Generate the Guile default module content + +guile.$(OBJEXT): gmk-default.h +gmk-default.h: $(srcdir)/gmk-default.scm + (echo 'static const char *const GUILE_module_defn = " '\\ \ + && sed -e 's/;.*//' -e '/^[ \t]*$$/d' -e 's/"/\\"/g' -e 's/$$/ \\/' \ + $(srcdir)/gmk-default.scm \ + && echo '";') > $@ + +# --------------- Local DIST Section + +# Install the w32 and tests subdirectories +# +dist-hook: + (cd $(srcdir); \ + sub=`find w32 tests -follow \( -name .git -o -name .deps -o -name work -o -name .gitignore -o -name \*.orig -o -name \*.rej -o -name \*~ -o -name Makefile \) -prune -o -type f -print`; \ + tar chf - $$sub) \ + | (cd $(distdir); tar xfBp -) + + +# --------------- Local CHECK Section + +check-local: check-regression check-loadavg + @banner=" Regression PASSED: GNU Make $(VERSION) ($(MAKE_HOST)) built with $(CC) "; \ + dashes=`echo "$$banner" | sed s/./=/g`; \ + echo; \ + echo "$$dashes"; \ + echo "$$banner"; \ + echo "$$dashes"; \ + echo + +.PHONY: check-loadavg check-regression + +check-loadavg: loadavg$(EXEEXT) + @echo The system uptime program believes the load average to be: + -uptime + @echo The GNU load average checking code thinks: + -./loadavg$(EXEEXT) + +# The loadavg function is invoked during "make check" to test getloadavg. +check_PROGRAMS = loadavg +nodist_loadavg_SOURCES = getloadavg.c +loadavg_CPPFLAGS = -DTEST +loadavg_LDADD = @GETLOADAVG_LIBS@ + +# > check-regression +# +# Look for the make test suite, and run it if found and we can find perl. +# If we're building outside the tree, we use symlinks to make a local copy of +# the test suite. Unfortunately the test suite itself isn't localizable yet. +# +MAKETESTFLAGS = + +check-regression: tests/config-flags.pm + @if test -f '$(srcdir)/tests/run_make_tests'; then \ + ulimit -n 128; \ + if $(PERL) -v >/dev/null 2>&1; then \ + case `cd '$(srcdir)'; pwd` in `pwd`) : ;; \ + *) test -d tests || mkdir tests; \ + rm -f srctests; \ + if ln -s '$(srcdir)/tests' srctests; then \ + for f in run_make_tests run_make_tests.pl test_driver.pl scripts; do \ + rm -f tests/$$f; ln -s ../srctests/$$f tests; \ + done; fi ;; \ + esac; \ + echo "cd tests && $(PERL) ./run_make_tests.pl -srcdir $(abs_srcdir) -make ../make$(EXEEXT) $(MAKETESTFLAGS)"; \ + cd tests && $(PERL) ./run_make_tests.pl -srcdir '$(abs_srcdir)' -make '../make$(EXEEXT)' $(MAKETESTFLAGS); \ + else \ + echo "Can't find a working Perl ($(PERL)); the test suite requires Perl."; \ + fi; \ + else \ + echo "Can't find the GNU Make test suite ($(srcdir)/tests)."; \ + fi + + +# --------------- Maintainer's Section + +# Tell automake that I haven't forgotten about this file and it will be +# created before we build a distribution (see maintMakefile in the Git +# distribution). + +README: + +@MAINT_MAKEFILE@ diff --git a/src/kmk/Makefile.ami b/src/kmk/Makefile.ami new file mode 100644 index 0000000..39a9788 --- /dev/null +++ b/src/kmk/Makefile.ami @@ -0,0 +1,308 @@ +# -*-Makefile-*- for GNU make on Amiga +# +# NOTE: If you have no 'make' program at all to process this makefile, run +# 'build.sh' instead. +# +# Copyright (C) 1995-2016 Free Software Foundation, Inc. +# This file is part of GNU Make. +# +# GNU Make is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +# +# Makefile for GNU Make +# + +CC = sc +RM = delete + +CFLAGS = +CPPFLAGS = +LDFLAGS = + +# Define these for your system as follows: +# -DNO_ARCHIVES To disable 'ar' archive support. +# -DNO_FLOAT To avoid using floating-point numbers. +# -DENUM_BITFIELDS If the compiler isn't GCC but groks enum foo:2. +# Some compilers apparently accept this +# without complaint but produce losing code, +# so beware. +# NeXT 1.0a uses an old version of GCC, which required -D__inline=inline. +# See also 'config.h'. +defines = + +# Which flavor of remote job execution support to use. +# The code is found in 'remote-$(REMOTE).c'. +REMOTE = stub + +# If you are using the GNU C library, or have the GNU getopt functions in +# your C library, you can comment these out. +GETOPT = getopt.o getopt1.o +GETOPT_SRC = $(srcdir)getopt.c $(srcdir)getopt1.c $(srcdir)getopt.h + +# If you are using the GNU C library, or have the GNU glob functions in +# your C library, you can comment this out. GNU make uses special hooks +# into the glob functions to be more efficient (by using make's directory +# cache for globbing), so you must use the GNU functions even if your +# system's C library has the 1003.2 glob functions already. Also, the glob +# functions in the AIX and HPUX C libraries are said to be buggy. +GLOB = glob/glob.lib + +# If your system doesn't have alloca, or the one provided is bad, define this. +ALLOCA = alloca.o +ALLOCA_SRC = $(srcdir)alloca.c + +# If your system needs extra libraries loaded in, define them here. +# System V probably need -lPW for alloca. HP-UX 7.0's alloca in +# libPW.a is broken on HP9000s300 and HP9000s400 machines. Use +# alloca.c instead on those machines. +LOADLIBES = + +# Any extra object files your system needs. +extras = amiga.o + +# Common prefix for machine-independent installed files. +prefix = +# Common prefix for machine-dependent installed files. +exec_prefix = + +# Directory to install 'make' in. +bindir = sc:c +# Directory to find libraries in for '-lXXX'. +libdir = lib: +# Directory to search by default for included makefiles. +includedir = include: +# Directory to install the Info files in. +infodir = doc: +# Directory to install the man page in. +mandir = t: +# Number to put on the man page filename. +manext = 1 +# Prefix to put on installed 'make' binary file name. +binprefix = +# Prefix to put on installed 'make' man page file name. +manprefix = $(binprefix) + +# Whether or not make needs to be installed setgid. +# The value should be either 'true' or 'false'. +# On many systems, the getloadavg function (used to implement the '-l' +# switch) will not work unless make is installed setgid kmem. +install_setgid = false +# Install make setgid to this group so it can read /dev/kmem. +group = sys + +# Program to install 'make'. +INSTALL_PROGRAM = copy +# Program to install the man page. +INSTALL_DATA = copy +# Generic install program. +INSTALL = copy + +# Program to format Texinfo source into Info files. +MAKEINFO = makeinfo +# Program to format Texinfo source into DVI files. +TEXI2DVI = texi2dvi + +# Programs to make tags files. +ETAGS = etags -w +CTAGS = ctags -w + +#guile = guile.o + +objs = commands.o job.o dir.o file.o misc.o main.o read.o remake.o \ + rule.o implicit.o default.o variable.o expand.o function.o \ + vpath.o version.o ar.o arscan.o signame.o strcache.o hash.o \ + remote-$(REMOTE).o $(GETOPT) $(ALLOCA) $(extras) $(guile) + +srcs = $(srcdir)commands.c $(srcdir)job.c $(srcdir)dir.c \ + $(srcdir)file.c $(srcdir)getloadavg.c $(srcdir)misc.c \ + $(srcdir)main.c $(srcdir)read.c $(srcdir)remake.c \ + $(srcdir)rule.c $(srcdir)implicit.c $(srcdir)default.c \ + $(srcdir)variable.c $(srcdir)expand.c $(srcdir)function.c \ + $(srcdir)vpath.c $(srcdir)version.c $(srcdir)hash.c \ + $(srcdir)guile.c $(srcdir)remote-$(REMOTE).c \ + $(srcdir)ar.c $(srcdir)arscan.c $(srcdir)strcache.c \ + $(srcdir)signame.c $(srcdir)signame.h $(GETOPT_SRC) \ + $(srcdir)commands.h $(srcdir)dep.h $(srcdir)filedep.h \ + $(srcdir)job.h $(srcdir)makeint.h $(srcdir)rule.h \ + $(srcdir)variable.h $(ALLOCA_SRC) $(srcdir)config.h.in + + +.SUFFIXES: +.SUFFIXES: .o .c .h .ps .dvi .info .texinfo + +all: make +info: make.info +dvi: make.dvi +# Some makes apparently use .PHONY as the default goal if it is before 'all'. +.PHONY: all check info dvi + +make.info: make.texinfo + $(MAKEINFO) -I$(srcdir) $(srcdir)make.texinfo -o make.info + +make.dvi: make.texinfo + $(TEXI2DVI) $(srcdir)make.texinfo + +make.ps: make.dvi + dvi2ps make.dvi > make.ps + +make: $(objs) $(GLOB) + $(CC) Link $(LDFLAGS) $(objs) Lib $(GLOB) $(LOADLIBES) To make.new + -delete make + rename make.new make + +TMPFILE = t:Make$$ + +$(GLOB): + cd glob @@\ + $(MAKE) -$(MAKEFLAGS) -f Makefile + +# -I. is needed to find config.h in the build directory. +OUTPUT_OPTION = +.c.o: + $(CC) $(defines) IDir "" IDir glob \ + $(CPPFLAGS) $(CFLAGS) $< $(OUTPUT_OPTION) + +# For some losing Unix makes. +SHELL = /bin/sh +#@SET_MAKE@ + +glob/libglob.a: FORCE config.h + cd glob; $(MAKE) libglob.a +FORCE: + +.PHONY: install installdirs +install: installdirs \ + $(bindir)$(binprefix)make $(infodir)make.info \ + $(mandir)$(manprefix)make.$(manext) + +installdirs: + $(SHELL) ${srcdir}/mkinstalldirs $(bindir) $(infodir) $(mandir) + +$(bindir)$(binprefix)make: make + $(INSTALL_PROGRAM) make $@.new + @if $(install_setgid); then \ + if chgrp $(group) $@.new && chmod g+s $@.new; then \ + echo "chgrp $(group) $@.new && chmod g+s $@.new"; \ + else \ + echo "$@ needs to be owned by group $(group) and setgid;"; \ + echo "otherwise the '-l' option will probably not work."; \ + echo "You may need special privileges to install $@."; \ + fi; \ + else true; fi +# Some systems can't deal with renaming onto a running binary. + -$(RM) $@.old + -mv $@ $@.old + mv $@.new $@ + +$(infodir)make.info: make.info + if [ -r ./make.info ]; then dir=.; else dir=$(srcdir); fi; \ + for file in $${dir}/make.info*; do \ + name="`basename $$file`"; \ + $(INSTALL_DATA) $$file \ + `echo $@ | sed "s,make.info\$$,$$name,"`; \ + done +# Run install-info only if it exists. +# Use 'if' instead of just prepending '-' to the +# line so we notice real errors from install-info. +# We use '$(SHELL) -c' because some shells do not +# fail gracefully when there is an unknown command. + if $(SHELL) -c 'install-info --version' >/dev/null 2>&1; then \ + if [ -r ./make.info ]; then dir=.; else dir=$(srcdir); fi; \ + install-info --infodir=$(infodir) $$dir/make.info; \ + else true; fi + +$(mandir)$(manprefix)make.$(manext): make.man + $(INSTALL_DATA) $(srcdir)make.man $@ + + +loadavg: loadavg.c config.h + $(CC) $(defines) -DTEST -I. -I$(srcdir) $(CFLAGS) $(LDFLAGS) \ + loadavg.c $(LOADLIBES) -o $@ +# We copy getloadavg.c into a different file rather than compiling it +# directly because some compilers clobber getloadavg.o in the process. +loadavg.c: getloadavg.c + ln $(srcdir)getloadavg.c loadavg.c || \ + cp $(srcdir)getloadavg.c loadavg.c +check-loadavg: loadavg + @echo The system uptime program believes the load average to be: + -uptime + @echo The GNU load average checking code believes: + ./loadavg +check: check-loadavg + + +.PHONY: clean realclean distclean mostlyclean +clean: glob-clean + -$(RM) make loadavg "#?.o" core make.dvi + +distclean: clean glob-realclean + -$(RM) Makefile config.h config.status build.sh + -$(RM) config.log config.cache + -$(RM) TAGS tags + -$(RM) make.?? make.??s make.log make.toc make.*aux + -$(RM) loadavg.c + +realclean: distclean + -$(RM) make.info* +mostlyclean: clean + +.PHONY: glob-clean glob-realclean +glob-clean glob-realclean: + cd glob @@\ + $(MAKE) $@ + +# This tells versions [3.59,3.63) of GNU make not to export all variables. +.NOEXPORT: + +# The automatically generated dependencies below may omit config.h +# because it is included with '#include ' rather than +# '#include "config.h"'. So we add the explicit dependency to make sure. +$(objs): config.h + +# Automatically generated dependencies will be put at the end of the file. + +# Automatically generated dependencies. +commands.o: commands.c makeint.h dep.h filedef.h variable.h job.h \ + commands.h +job.o: job.c makeint.h job.h filedef.h commands.h variable.h +dir.o: dir.c makeint.h +file.o: file.c makeint.h dep.h filedef.h job.h commands.h variable.h +misc.o: misc.c makeint.h dep.h +main.o: main.c makeint.h dep.h filedef.h variable.h job.h commands.h \ + getopt.h +guile.o: guile.c makeint.h dep.h debug.h variable.h gmk-default.h +read.o: read.c makeint.h dep.h filedef.h job.h commands.h variable.h \ + glob/glob.h +remake.o: remake.c makeint.h filedef.h job.h commands.h dep.h +rule.o: rule.c makeint.h dep.h filedef.h job.h commands.h variable.h \ + rule.h +implicit.o: implicit.c makeint.h rule.h dep.h filedef.h +default.o: default.c makeint.h rule.h dep.h filedef.h job.h commands.h \ + variable.h +variable.o: variable.c makeint.h dep.h filedef.h job.h commands.h \ + variable.h +expand.o: expand.c makeint.h filedef.h job.h commands.h variable.h +function.o: function.c makeint.h filedef.h variable.h dep.h job.h \ + commands.h amiga.h +vpath.o: vpath.c makeint.h filedef.h variable.h +strcache.o: strcache.c makeint.h hash.h +version.o: version.c +ar.o: ar.c makeint.h filedef.h dep.h +arscan.o: arscan.c makeint.h +signame.o: signame.c signame.h +remote-stub.o: remote-stub.c makeint.h filedef.h job.h commands.h +getopt.o: getopt.c +getopt1.o : getopt1.c getopt.h +getloadavg.o: getloadavg.c +amiga.o: amiga.c makeint.h variable.h amiga.h diff --git a/src/kmk/Makefile.kmk b/src/kmk/Makefile.kmk new file mode 100644 index 0000000..ff93ae5 --- /dev/null +++ b/src/kmk/Makefile.kmk @@ -0,0 +1,770 @@ +# $Id: Makefile.kmk 3572 2022-10-24 08:36:35Z bird $ +## @file +# Sub-makefile for kmk / GNU Make. +# + +# +# Copyright (c) 2004-2011 knut st. osmundsen +# +# This file is part of kBuild. +# +# kBuild is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# kBuild is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with kBuild. If not, see +# +# + +SUB_DEPTH = ../.. +include $(KBUILD_PATH)/subheader.kmk + +# Enable new children handling for windows. +CONFIG_NEW_WIN_CHILDREN = 1 + +# +# Template for kmk and the kmk_* binaries in this makefile. +# +TEMPLATE_BIN-KMK = Template for src/gmake binaries +TEMPLATE_BIN-KMK_EXTENDS = BIN-THREADED +TEMPLATE_BIN-KMK_DEFS = \ + HAVE_CONFIG_H \ + $(TEMPLATE_BIN_DEFS) \ + KBUILD_SVN_REV=$(KBUILD_SVN_REV) \ + KBUILD_TYPE=$(TMP_QUOTE_SLASH)"$(KBUILD_TYPE)$(TMP_QUOTE_SLASH)" +TEMPLATE_BIN-KMK_DEPS = \ + $(kmk_0_OUTDIR)/config.h \ + $(kmk_0_OUTDIR)/fts.h +TEMPLATE_BIN-KMK_CLEAN = $(TEMPLATE_BIN-KMK_DEPS) +TEMPLATE_BIN-KMK_DEPS.solaris = \ + $(kmk_0_OUTDIR)/paths.h +TEMPLATE_BIN-KMK_CLEAN.solaris = $(TEMPLATE_BIN-KMK_DEPS.solaris) +TEMPLATE_BIN-KMK_DEPS.win = \ + $(kmk_0_OUTDIR)/sysexits.h \ + $(kmk_0_OUTDIR)/unistd.h \ + $(kmk_0_OUTDIR)/paths.h \ + $(kmk_0_OUTDIR)/grp.h \ + $(kmk_0_OUTDIR)/pwd.h \ + $(kmk_0_OUTDIR)/inttypes.h +TEMPLATE_BIN-KMK_CFLAGS.win.amd64 = $(TEMPLATE_BIN-THREADED_CFLAGS.win.amd64) -wd4244 -wd4267 +TEMPLATE_BIN-KMK_CLEAN.win = $(TEMPLATE_BIN-KMK_DEPS.win) +TEMPLATE_BIN-KMK_DEFS.debug = $(TEMPLATE_BIN_DEFS.debug) MAKE_MAINTAINER_MODE +TEMPLATE_BIN-KMK_INCS = $(kmk_0_OUTDIR) . $(TEMPLATE_BIN-THREADED_INCS) +ifneq ($(KBUILD_TARGET),os2) + TEMPLATE_BIN-KMK_INCS += glob +endif +TEMPLATE_BIN-KMK_LIBS = $(LIB_KUTIL) $(TEMPLATE_BIN-THREADED_LIBS) $(kmkmissing_1_TARGET) $(LIB_KUTIL) +TEMPLATE_BIN-KMK_LIBS.x86 = $(LIB_KUTIL) $(TEMPLATE_BIN-THREADED_LIBS.x86) +TEMPLATE_BIN-KMK_LIBS.amd64 = $(LIB_KUTIL) $(TEMPLATE_BIN-THREADED_LIBS.amd64) +ifdef ELECTRIC_HEAP # for electric heap (see electric.c). +ifeq ($(KBUILD_TARGET),win) + TEMPLATE_BIN-KMK_CFLAGS = $(TEMPLATE_BIN-THREADED_CFLAGS) /FI$(kmk_DEFPATH)/electric.h -DELECTRIC_HEAP=1 +else + TEMPLATE_BIN-KMK_CFLAGS = $(TEMPLATE_BIN-THREADED_CFLAGS) -include $(kmk_DEFPATH)/electric.h -DELECTRIC_HEAP=1 +endif +endif +ifdef CONFIG_WITH_ALLOCCACHE_DEBUG + TEMPLATE_BIN-KMK_DEFS += CONFIG_WITH_ALLOCCACHE_DEBUG +endif +ifdef CONFIG_NEW_WIN_CHILDREN + TEMPLATE_BIN-KMK_DEFS.win = $(TEMPLATE_BIN_DEFS.win) CONFIG_NEW_WIN_CHILDREN +endif +# GCC sanitizers. +ifdef GCC_SANITIZERS + TEMPLATE_BIN-KMK_CFLAGS ?= $(TEMPLATE_BIN-THREADED_CFLAGS) +# TEMPLATE_BIN-KMK_CFLAGS += -fsanitize=address -fsanitize=undefined -static-libubsan -D GCC_ADDRESS_SANITIZER + TEMPLATE_BIN-KMK_CFLAGS += -fsanitize=address -fsanitize=undefined -D GCC_ADDRESS_SANITIZER + TEMPLATE_BIN-KMK_LDFLAGS ?= $(TEMPLATE_BIN-THREADED_LDFLAGS) + TEMPLATE_BIN-KMK_LDFLAGS += -fsanitize=address -fsanitize=undefined +endif + +# +# Library version of the above. +# +TEMPLATE_LIB-KMK = Template for src/gmake libraries +TEMPLATE_LIB-KMK_EXTENDS = BIN-KMK +TEMPLATE_LIB-KMK_POST_CMDS.win = $(NO_SUCH_VARIABLE) + +# +# Template for building standalone built-in utilities. +# +TEMPLATE_BIN-KMK-BUILTIN = Template for standalone built-in utilies. +TEMPLATE_BIN-KMK-BUILTIN_EXTENDS = BIN-KMK +TEMPLATE_BIN-KMK-BUILTIN_EXTENDS_BY = appending +TEMPLATE_BIN-KMK-BUILTIN_DEFS += KMK_BUILTIN_STANDALONE +TEMPLATE_BIN-KMK-BUILTIN_SOURCES += kmkbuiltin/err.c + +# +# A library containing the missing features needed by kmk and the +# kmk_* binaries. Saves a bit of work later on. +# +LIBRARIES += kmkmissing +kmkmissing_TEMPLATE = LIB-KMK +kmkmissing_DEFS = KMK +kmkmissing_NOINST = 1 +kmkmissing_SOURCES = \ + kmkbuiltin/fts.c \ + kmkbuiltin/setmode.c \ + kmkbuiltin/strmode.c \ + kmkbuiltin/kbuild_protection.c \ + kmkbuiltin/common-env-and-cwd-opt.c \ + kmkbuiltin/getopt_r.c \ + kmkbuiltin/getopt1_r.c \ + getopt.c \ + getopt1.c \ + electric.c +ifneq ($(KBUILD_TARGET),os2) +kmkmissing_SOURCES += \ + glob/glob.c +endif + +kmkmissing_SOURCES.darwin = \ + kmkbuiltin/darwin.c \ + glob/fnmatch.c + +kmkmissing_SOURCES.dragonfly = \ + glob/fnmatch.c + +kmkmissing_SOURCES.freebsd = \ + glob/fnmatch.c + +kmkmissing_SOURCES.gnuhurd += \ + kmkbuiltin/strlcpy.c + +kmkmissing_SOURCES.gnukfbsd += \ + kmkbuiltin/strlcpy.c + +kmkmissing_SOURCES.gnuknbsd += \ + kmkbuiltin/strlcpy.c + +kmkmissing_SOURCES.haiku = \ + kmkbuiltin/haikufakes.c \ + glob/fnmatch.c + +kmkmissing_SOURCES.linux += \ + kmkbuiltin/strlcpy.c + +kmkmissing_SOURCES.netbsd = \ + glob/fnmatch.c + +kmkmissing_SOURCES.openbsd = \ + kmkbuiltin/openbsd.c + +kmkmissing_SOURCES.solaris = \ + kmkbuiltin/strlcpy.c \ + kmkbuiltin/solfakes.c \ + glob/fnmatch.c + +kmkmissing_SOURCES.win += \ + kmkbuiltin/strlcpy.c \ + kmkbuiltin/mscfakes.c \ + glob/fnmatch.c \ + getloadavg.c \ + w32/subproc/misc.c \ + w32/subproc/w32err.c \ + w32/pathstuff.c \ + w32/imagecache.c \ + w32/compat/posixfcn.c + +# +# kmk +# +PROGRAMS += kmk + +kmk_TEMPLATE = BIN-KMK + +kmk_DEFS = \ + NO_ARCHIVES \ + EXPERIMENTAL \ + CONFIG_WITH_TOUPPER_TOLOWER \ + CONFIG_WITH_DEFINED \ + CONFIG_WITH_EXPLICIT_MULTITARGET \ + CONFIG_WITH_DOT_MUST_MAKE \ + CONFIG_WITH_PREPEND_ASSIGNMENT \ + CONFIG_WITH_LOCAL_VARIABLES \ + CONFIG_WITH_2ND_TARGET_EXPANSION \ + CONFIG_WITH_ALLOC_CACHES \ + CONFIG_WITH_STRCACHE2 \ + \ + KMK \ + KMK_HELPERS \ + CONFIG_NO_DEFAULT_SUFFIXES \ + CONFIG_NO_DEFAULT_PATTERN_RULES \ + CONFIG_NO_DEFAULT_TERMINAL_RULES \ + CONFIG_NO_DEFAULT_SUFFIX_RULES \ + CONFIG_NO_DEFAULT_VARIABLES \ + \ + CONFIG_WITH_ABSPATHEX \ + CONFIG_WITH_COMMANDS_FUNC \ + CONFIG_WITH_DATE \ + CONFIG_WITH_DEFINED_FUNCTIONS \ + CONFIG_WITH_EVALPLUS \ + CONFIG_WITH_FILE_SIZE \ + CONFIG_WITH_LOOP_FUNCTIONS \ + CONFIG_WITH_MATH \ + CONFIG_WITH_NANOTS \ + CONFIG_WITH_ROOT_FUNC \ + CONFIG_WITH_RSORT \ + CONFIG_WITH_STACK \ + CONFIG_WITH_STRING_FUNCTIONS \ + CONFIG_WITH_WHERE_FUNCTION \ + CONFIG_WITH_WHICH \ + CONFIG_WITH_XARGS \ + \ + CONFIG_WITH_EXTENDED_NOTPARALLEL \ + CONFIG_WITH_INCLUDEDEP \ + CONFIG_WITH_VALUE_LENGTH \ + CONFIG_WITH_COMPARE \ + CONFIG_WITH_SET_CONDITIONALS \ + CONFIG_WITH_IF_CONDITIONALS \ + CONFIG_WITH_PRINTF \ + CONFIG_WITH_MINIMAL_STATS \ + \ + CONFIG_PRETTY_COMMAND_PRINTING \ + CONFIG_WITH_PRINT_STATS_SWITCH \ + CONFIG_WITH_PRINT_TIME_SWITCH \ + CONFIG_WITH_RDONLY_VARIABLE_VALUE \ + CONFIG_WITH_LAZY_DEPS_VARS \ + CONFIG_WITH_MEMORY_OPTIMIZATIONS \ + \ + KBUILD_HOST=$(TMP_QUOTE_SLASH)"$(KBUILD_TARGET)$(TMP_QUOTE_SLASH)" \ + KBUILD_HOST_ARCH=$(TMP_QUOTE_SLASH)"$(KBUILD_TARGET_ARCH)$(TMP_QUOTE_SLASH)" \ + KBUILD_HOST_CPU=$(TMP_QUOTE_SLASH)"$(KBUILD_TARGET_CPU)$(TMP_QUOTE_SLASH)" +# kmk_DEFS += CONFIG_WITH_COMPILER # experimental, doesn't work 101% right it seems. +kmk_DEFS.x86 = CONFIG_WITH_OPTIMIZATION_HACKS +kmk_DEFS.amd64 = CONFIG_WITH_OPTIMIZATION_HACKS +kmk_DEFS.win = CONFIG_NEW_WIN32_CTRL_EVENT CONFIG_WITH_OUTPUT_IN_MEMORY +kmk_DEFS.debug = CONFIG_WITH_MAKE_STATS +ifdef CONFIG_WITH_MAKE_STATS + kmk_DEFS += CONFIG_WITH_MAKE_STATS +endif +#ifdef CONFIG_WITH_KMK_BUILTIN_STATS + kmk_DEFS += CONFIG_WITH_KMK_BUILTIN_STATS +#endif +ifdef CONFIG_WITH_EVAL_COMPILER + kmk_DEFS += CONFIG_WITH_EVAL_COMPILER +endif +ifdef CONFIG_WITH_COMPILE_EVERYTHING + kmk_DEFS += CONFIG_WITH_COMPILE_EVERYTHING +endif + +#ifeq ($(KBUILD_TYPE).$(USERNAME),debug.bird) +# kmk_DEFS += CONFIG_WITH_COMPILER CONFIG_WITH_EVAL_COMPILER CONFIG_WITH_COMPILE_EVERYTHING +#endif + +kmk_SOURCES = \ + main.c \ + read.c \ + hash.c \ + strcache.c \ + variable.c \ + ar.c \ + arscan.c \ + commands.c \ + default.c \ + expand.c \ + file.c \ + function.c \ + implicit.c \ + job.c \ + misc.c \ + output.c \ + remake.c \ + rule.c \ + signame.c \ + version.c \ + vpath.c \ + remote-stub.c \ + guile.c \ + load.c \ + \ + alloccache.c \ + expreval.c \ + incdep.c \ + strcache2.c \ + kmk_cc_exec.c \ + kbuild.c \ + kbuild-object.c +ifeq ($(KBUILD_TARGET),win) + kmk_SOURCES += \ + dir-nt-bird.c \ + w32/w32os.c +else + kmk_SOURCES += \ + dir.c \ + posixos.c +endif + +ifndef CONFIG_NEW_WIN_CHILDREN +kmk_SOURCES.win = \ + w32/subproc/sub_proc.c +else +kmk_SOURCES.win = \ + w32/winchildren.c +endif + +kmk_DEFS.freebsd.x86 = CONFIG_WITHOUT_THREADS + +#kmk_LIBS.solaris = malloc +#kmk_DEFS.solaris += HAVE_MALLINFO + +# +# kmkbuiltin commands +# +kmk_DEFS += CONFIG_WITH_KMK_BUILTIN +kmk_LIBS += $(LIB_KUTIL) #$(LIB_KDEP) +kmk_SOURCES += \ + kmkbuiltin.c \ + kmkbuiltin/append.c \ + kmkbuiltin/cat.c \ + kmkbuiltin/chmod.c \ + kmkbuiltin/cmp.c \ + kmkbuiltin/cmp_util.c \ + kmkbuiltin/cp.c \ + kmkbuiltin/cp_utils.c \ + kmkbuiltin/echo.c \ + kmkbuiltin/expr.c \ + kmkbuiltin/install.c \ + kmkbuiltin/kDepIDB.c \ + kmkbuiltin/kDepObj.c \ + ../lib/kDep.c \ + kmkbuiltin/md5sum.c \ + kmkbuiltin/mkdir.c \ + kmkbuiltin/mv.c \ + kmkbuiltin/ln.c \ + kmkbuiltin/printf.c \ + kmkbuiltin/redirect.c \ + kmkbuiltin/rm.c \ + kmkbuiltin/rmdir.c \ + $(if-expr $(KBUILD_TARGET) == win,kmkbuiltin/kSubmit.c) \ + kmkbuiltin/sleep.c \ + kmkbuiltin/test.c \ + kmkbuiltin/touch.c \ + \ + kmkbuiltin/err.c +kmk_SOURCES.win += \ + kmkbuiltin/kill.c + + +## @todo kmkbuiltin/redirect.c + +## Some profiling +#kmk_SOURCES += kbuildprf.c +#kmk_DEFS += open=prf_open read=prf_read lseek=prf_lseek close=prf_close +##kmk_DEFS += KMK_PRF=1 +##kmkmissing_DEFS += KMK_PRF=1 + +# +# Standalone kmkbuiltin commands. +# +PROGRAMS += \ + kmk_append \ + kmk_cat \ + kmk_chmod \ + kmk_cp \ + kmk_cmp \ + kmk_echo \ + kmk_expr \ + kmk_md5sum \ + kmk_mkdir \ + kmk_mv \ + kmk_install \ + kmk_ln \ + kmk_printf \ + kmk_redirect \ + kmk_rm \ + kmk_rmdir \ + kmk_sleep \ + kmk_test \ + kmk_touch \ + kDepIDB \ + kDepObj +PROGRAMS.win += \ + kmk_kill + +kmk_append_TEMPLATE = BIN-KMK-BUILTIN +kmk_append_INCS = . +kmk_append_SOURCES = \ + kmkbuiltin/append.c + +kmk_cat_TEMPLATE = BIN-KMK-BUILTIN +kmk_cat_SOURCES = \ + kmkbuiltin/cat.c + +kmk_chmod_TEMPLATE = BIN-KMK-BUILTIN +kmk_chmod_SOURCES = \ + kmkbuiltin/chmod.c + +kmk_cmp_TEMPLATE = BIN-KMK-BUILTIN +kmk_cmp_SOURCES = \ + kmkbuiltin/cmp.c \ + kmkbuiltin/cmp_util.c + +kmk_cp_TEMPLATE = BIN-KMK-BUILTIN +kmk_cp_SOURCES = \ + kmkbuiltin/cp.c \ + kmkbuiltin/cp_utils.c \ + kmkbuiltin/cmp_util.c + +kmk_echo_TEMPLATE = BIN-KMK-BUILTIN +kmk_echo_SOURCES = \ + kmkbuiltin/echo.c + +kmk_expr_TEMPLATE = BIN-KMK-BUILTIN +kmk_expr_SOURCES = \ + kmkbuiltin/expr.c + +kmk_install_TEMPLATE = BIN-KMK-BUILTIN +kmk_install_SOURCES = \ + kmkbuiltin/install.c + +kmk_kill_TEMPLATE = BIN-KMK-BUILTIN +kmk_kill_SOURCES = \ + kmkbuiltin/kill.c + +kmk_ln_TEMPLATE = BIN-KMK-BUILTIN +kmk_ln_SOURCES = \ + kmkbuiltin/ln.c + +kmk_mkdir_TEMPLATE = BIN-KMK-BUILTIN +kmk_mkdir_SOURCES = \ + kmkbuiltin/mkdir.c + +kmk_md5sum_TEMPLATE = BIN-KMK-BUILTIN +kmk_md5sum_SOURCES = \ + kmkbuiltin/md5sum.c +kmk_md5sum_LIBS = $(LIB_KUTIL) + +kmk_mv_TEMPLATE = BIN-KMK-BUILTIN +kmk_mv_SOURCES = \ + kmkbuiltin/mv.c + +kmk_printf_TEMPLATE = BIN-KMK-BUILTIN +kmk_printf_SOURCES = \ + kmkbuiltin/printf.c + +kmk_rm_TEMPLATE = BIN-KMK-BUILTIN +kmk_rm_SOURCES = \ + kmkbuiltin/rm.c + +kmk_redirect_TEMPLATE = BIN-KMK-BUILTIN +kmk_redirect_SOURCES = \ + kmkbuiltin/redirect.c +kmk_redirect_SOURCES.win = \ + ../lib/startuphacks-win.c + +kmk_rmdir_TEMPLATE = BIN-KMK-BUILTIN +kmk_rmdir_SOURCES = \ + kmkbuiltin/rmdir.c + +kmk_sleep_TEMPLATE = BIN-KMK-BUILTIN +kmk_sleep_SOURCES = \ + kmkbuiltin/sleep.c + +kmk_test_TEMPLATE = BIN-KMK-BUILTIN +kmk_test_SOURCES = \ + kmkbuiltin/test.c + +kmk_touch_TEMPLATE = BIN-KMK-BUILTIN +kmk_touch_SOURCES = \ + kmkbuiltin/touch.c + +kDepIDB_TEMPLATE = BIN-KMK-BUILTIN +kDepIDB_INCS = . +kDepIDB_LIBS = $(LIB_KDEP) $(LIB_KUTIL) +kDepIDB_SOURCES = \ + kmkbuiltin/kDepIDB.c + +kDepObj_TEMPLATE = BIN-KMK-BUILTIN +kDepObj_INCS = . +kDepObj_LIBS = $(LIB_KDEP) $(LIB_KUTIL) +kDepObj_SOURCES = \ + kmkbuiltin/kDepObj.c + + +# +# kmk_gmake - almost plain GNU Make. +# +PROGRAMS += kmk_gmake + +kmk_gmake_TEMPLATE = BIN-KMK +kmk_gmake_DEFS = \ + HAVE_CONFIG_H \ + CONFIG_WITH_TOUPPER_TOLOWER \ + EXPERIMENTAL +# NO_ARCHIVES + +kmk_gmake_SOURCES = \ + main.c \ + read.c \ + hash.c \ + strcache.c \ + variable.c \ + ar.c \ + arscan.c \ + commands.c \ + default.c \ + dir.c \ + expand.c \ + file.c \ + function.c \ + implicit.c \ + job.c \ + misc.c \ + output.c \ + remake.c \ + rule.c \ + signame.c \ + version.c \ + vpath.c \ + remote-stub.c \ + guile.c \ + load.c +ifeq ($(KBUILD_TARGET),win) + kmk_gmake_SOURCES += \ + w32/w32os.c +else + kmk_gmake_SOURCES += \ + posixos.c +endif + +ifndef CONFIG_NEW_WIN_CHILDREN +kmk_gmake_SOURCES.win = \ + w32/subproc/sub_proc.c +else +kmk_gmake_SOURCES.win = \ + w32/winchildren.c +endif + + +# +# kmk_fmake - Faster GNU Make. +# +ifeq ($(USER),bird) # for experimental purposes only. +PROGRAMS += kmk_fgmake +endif + +kmk_fgmake_TEMPLATE = BIN-KMK +kmk_fgmake_DEFS = \ + HAVE_CONFIG_H \ + NO_ARCHIVES \ + CONFIG_WITH_TOUPPER_TOLOWER \ + EXPERIMENTAL \ + \ + CONFIG_WITH_ALLOC_CACHES \ + CONFIG_WITH_LAZY_DEPS_VARS \ + CONFIG_WITH_STRCACHE2 \ + CONFIG_WITH_VALUE_LENGTH \ + CONFIG_WITH_RDONLY_VARIABLE_VALUE +# TODO ? +# CONFIG_WITH_PRINT_STATS_SWITCH \ +# CONFIG_WITH_EXTENDED_NOTPARALLEL \ + +kmk_fgmake_SOURCES = \ + main.c \ + read.c \ + hash.c \ + strcache.c \ + strcache2.c \ + variable.c \ + ar.c \ + arscan.c \ + commands.c \ + default.c \ + dir.c \ + expand.c \ + file.c \ + function.c \ + implicit.c \ + job.c \ + misc.c \ + output.c \ + alloccache.c \ + remake.c \ + rule.c \ + signame.c \ + version.c \ + vpath.c \ + remote-stub.c \ + guile.c \ + load.c +ifeq ($(KBUILD_TARGET),win) + kmk_fgmake_SOURCES += \ + w32/w32os.c +# @todo: dir-nt-bird.c for fgmake +else + kmk_fgmake_SOURCES += \ + posixos.c +endif + +kmk_fgmake_SOURCES.win = \ + w32/subproc/sub_proc.c + + +# +# tstFileInfo +# +PROGRAMS.win += tstFileInfo +tstFileInfo_TEMPLATE = BIN +tstFileInfo_SOURCES = w32/tstFileInfo.c + +# +# tstFileInfo +# +PROGRAMS.win += tstFtsFake +tstFtsFake_TEMPLATE = BIN-KMK +tstFtsFake_NOINST = 1 +tstFtsFake_DEFS = USE_OLD_FTS +tstFtsFake_SOURCES = ../lib/nt/tstNtFts.c + + + +include $(FILE_KBUILD_SUB_FOOTER) + + +# +# Use checked in config.h instead of running ./Configure for it. +# +kmk_config.h.$(KBUILD_TARGET) := $(kmk_DEFPATH)/config.h.$(KBUILD_TARGET) +$(kmk_0_OUTDIR)/config.h: $(kmk_config.h.$(KBUILD_TARGET)) + $(MKDIR) -p $(dir $@) + $(CP) $^ $@ + +# +# Some missing headers. +# +if1of ($(KBUILD_TARGET), win nt) +$(kmk_0_OUTDIR)/fts.h: $(MAKEFILE) | $(call DIRDEP,$(kmk_0_OUTDIR)) + $(APPEND) -t "$@" "#include " +else +$(kmk_0_OUTDIR)/fts.h: $(kmk_DEFPATH)/kmkbuiltin/ftsfake.h | $(call DIRDEP,$(kmk_0_OUTDIR)) + $(CP) $^ $@ +endif + +$(kmk_0_OUTDIR)/unistd.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) + $(ECHO_EXT) > $@ + +$(kmk_0_OUTDIR)/sysexits.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) + $(ECHO_EXT) > $@ + +$(kmk_0_OUTDIR)/inttypes.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) + $(ECHO_EXT) > $@ + +$(kmk_0_OUTDIR)/paths.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) + $(ECHO_EXT) > $@ + +$(kmk_0_OUTDIR)/pwd.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) + $(ECHO_EXT) > $@ + +$(kmk_0_OUTDIR)/grp.h: | $(call DIRDEP,$(kmk_0_OUTDIR)) + $(ECHO_EXT) > $@ + + +# +# Some tests. +# +parallel: parallel_1 parallel_2 parallel_3 parallel_4 parallel_5 +parallel_1 parallel_2 parallel_3 parallel_4 parallel_5: + echo $@_start ; sleep 1; echo $@_done + +my_test: + echo "1" + echo "2" + echo "3" + echo "4" + + +# +# Shell execution tests. +# +test_shell: test_shell_quoting test_shell_double_quoting test_shell_newline + +# shell double and single quoting check (was busted on windows in 3.81). +test_shell_quoting: + $(ECHO_EXT) "double quoted sTrInG" + $(ECHO_EXT) "double quoted sTrInG" | $(SED_EXT) -e "s/sTrInG/string/g" + $(ECHO_EXT) 'single quoted sTrInG' | $(SED_EXT) -e 's/sTrInG/string/g' + $(ECHO) "This string should not be printed with double quotes." + $(ECHO) 'This string should not be printed with single quotes.' + ( echo " #define PWD \"`pwd`\""; ) + +test_shell_double_quoting: + $(ECHO_EXT) "foo foo foo" | $(SED_EXT) -e \ + "s/foo/$@/" -e \ + "s/foo/works/" \ + -e "s/foo/\!/" + +test_shell_double_quoting2: + $(ECHO_EXT) "foo foo foo" | $(SED_EXT) -e \ + "s/foo/$@/" -e \ + "s/foo/works/" \ + -e\ + "s/foo/\!/" + +# when using batch mode shell, the newline got escaped twice and spoiling everything. +test_shell_newline: + $(ECHO_EXT) "foo foo foo" | $(SED_EXT) -e \ + 's/foo/$@/' -e \ + 's/foo/works/' \ + -e 's/foo/\!/' + + +test_stack: + $(MAKE) -f $(kmk_DEFPATH)/testcase-stack.kmk + +test_math: + $(MAKE) -f $(kmk_DEFPATH)/testcase-math.kmk + +test_if1of: + $(MAKE) -f $(kmk_DEFPATH)/testcase-if1of.kmk + +test_local: + $(MAKE) -f $(kmk_DEFPATH)/testcase-local.kmk + +test_includedep: + $(MAKE) -f $(kmk_DEFPATH)/testcase-includedep.kmk + +test_root: + $(MAKE) -f $(kmk_DEFPATH)/testcase-root.kmk + +test_2ndtargetexp: + $(MAKE) -f $(kmk_DEFPATH)/testcase-2ndtargetexp.kmk + +test_30_continued_on_failure_worker: + this_executable_does_not_exist.exe + echo "We shouldn't see this..." + +test_30_continued_on_failure: + $(MAKE) -f $(MAKEFILE) test_30_continued_on_failure_worker; \ + RC=$$?; \ + if test $${RC} -ne 2; then \ + echo "$@: FAILED - exit code $${RC} instead of 2."; \ + exit 1; \ + else \ + echo "$@: SUCCESS"; \ + fi + +test_lazy_deps_vars: + $(MAKE) -C $(kmk_DEFPATH) -f testcase-lazy-deps-vars.kmk + + +test_all: \ + test_math \ + test_stack \ + test_shell \ + test_if1of \ + test_local \ + test_root \ + test_includedep \ + test_2ndtargetexp \ + test_30_continued_on_failure \ + test_lazy_deps_vars + + diff --git a/src/kmk/Makefile.os2 b/src/kmk/Makefile.os2 new file mode 100644 index 0000000..5f61dde --- /dev/null +++ b/src/kmk/Makefile.os2 @@ -0,0 +1,47 @@ +# $Id: Makefile.os2 200 2004-12-17 14:05:38Z bird $ + +OBJDIR = objdir/OS2.libc +#OBJDIR = . +SRC = ar.c arscan.c commands.c default.c dir.c expand.c file.c \ + function.c implicit.c job.c main.c \ + misc.c read.c remake.c rule.c signame.c \ + variable.c version.c vpath.c hash.c \ + getopt.c getopt1.c remote-stub.c +OBJS = $(addprefix $(OBJDIR)/, $(SRC:.c=.obj)) +CFLAGS = -Zomf -g -Wall -I$(OBJDIR) -I. -DCONFIG_NO_DEFAULT_SUFFIXES \ + -DCONFIG_NO_DEFAULT_PATTERN_RULES -DCONFIG_NO_DEFAULT_TERMINAL_RULES \ + -DCONFIG_NO_DEFAULT_SUFFIX_RULES -DCONFIG_NO_DEFAULT_VARIABLES +ifndef DEBUG +CFLAGS += -O3 +endif +#-DMAKE_DLLSHELL + +all: $(OBJDIR) $(OBJDIR)/make-new.exe + +clean: + rm -f $(OBJS) $(OBJDIR)/make-new.exe $(OBJDIR)/config.h + +$(OBJDIR)/make-new.exe: $(OBJDIR)/config.h $(OBJS) + gcc -g $(CFLAGS) -Zhigh-mem -Zstack 1024 -o $@ $(OBJS) + +$(OBJDIR)/%.obj : %.c + gcc -c $(CFLAGS) -o $@ -DHAVE_CONFIG_H $< + +$(OBJDIR)/config.h: config.h.os2 + cp $< $@ + +$(OBJDIR): + mkdir.exe -p $@ + +test: + echo "1" + echo "2" + echo "3" + echo "4" + +parallel: parallel_1 parallel_2 parallel_3 parallel_4 parallel_5 + +parallel_1 parallel_2 parallel_3 parallel_4 parallel_5: + echo $@_start ; sleep 1; echo $@_done + + diff --git a/src/kmk/NEWS b/src/kmk/NEWS new file mode 100644 index 0000000..0b04245 --- /dev/null +++ b/src/kmk/NEWS @@ -0,0 +1,1540 @@ +GNU make NEWS -*-indented-text-*- + History of user-visible changes. + 10 June 2016 + +See the end of this file for copyrights and conditions. + +All changes mentioned here are more fully described in the GNU make +manual, which is contained in this distribution as the file doc/make.texi. +See the README file and the GNU make manual for instructions for +reporting bugs. + +Version 4.2.1 (10 Jun 2016) + +A complete list of bugs fixed in this version is available here: +h +ttp://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=107&set=custom + +This release is a bug-fix release. + + +Version 4.2 (22 May 2016) + +A complete list of bugs fixed in this version is available here: + +http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=106&set=custom + +* New variable: $(.SHELLSTATUS) is set to the exit status of the last != or + $(shell ...) function invoked in this instance of make. This will be "0" if + successful or not "0" if not successful. The variable value is unset if no + != or $(shell ...) function has been invoked. + +* The $(file ...) function can now read from a file with $(file + +* The interface to GNU make's "jobserver" is stable as documented in the + manual, for tools which may want to access it. + + WARNING: Backward-incompatibility! The internal-only command line option + --jobserver-fds has been renamed for publishing, to --jobserver-auth. + +* The amount of parallelism can be determined by querying MAKEFLAGS, even when + the job server is enabled (previously MAKEFLAGS would always contain only + "-j", with no number, when job server was enabled). + +* VMS-specific changes: + + * Perl test harness now works. + + * Full support for converting Unix exit status codes to VMS exit status + codes. BACKWARD INCOMPATIBILITY Notice: On a child failure the VMS exit + code is now the encoded Unix exit status that Make usually generates, not + the VMS exit status of the child. + + +Version 4.1 (05 Oct 2014) + +A complete list of bugs fixed in this version is available here: + +http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=105&set=custom + +* New variables: $(MAKE_TERMOUT) and $(MAKE_TERMERR) are set to non-empty + values if stdout or stderr, respectively, are believed to be writing to a + terminal. These variables are exported by default. + +* Allow a no-text-argument form of the $(file ...) function. Without a text + argument nothing is written to the file: it is simply opened in the + requested mode, then closed again. + +* Change the fatal error for mixed explicit and implicit rules, that was + introduced in GNU make 3.82, to a non-fatal error. However, this syntax is + still deprecated and may return to being illegal in a future version of GNU + make. Makefiles that rely on this syntax should be fixed. + See https://savannah.gnu.org/bugs/?33034 + +* VMS-specific changes: + + * Support for library files added, including support for using the GNV ar + utility. + + * Partial support for properly encoding Unix exit status codes into VMS exit + status codes. + + WARNING: Backward-incompatibility! These are different exit status codes + than Make exited with in the past. + + * Macros to hold the current make command are set up to translate the + argv[0] string to a VMS format path name and prefix it with "MCR " so that + the macro has a space in it. + + WARNING: Backward-incompatibility! This may break complex makefiles that + do processing on those macros. This is unlikely because so much in that + area was not and is still not currently working on VMS, it is unlikely to + find such a complex makefile, so this is more likely to impact + construction of a future makefile. + + * A command file is always used to run the commands for a recipe. + + WARNING: Backward-incompatibility! Running the make self tests has + exposed that there are significant differences in behavior when running + with the command file mode. It is unknown if this will be noticed by most + existing VMS makefiles. + +Version 4.0 (09 Oct 2013) + +A complete list of bugs fixed in this version is available here: + +http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=101&set=custom + +* WARNING: Backward-incompatibility! + If .POSIX is specified, then make adheres to the POSIX backslash/newline + handling requirements, which introduces the following changes to the + standard backslash/newline handling in non-recipe lines: + * Any trailing space before the backslash is preserved + * Each backslash/newline (plus subsequent whitespace) is converted to a + single space + +* New feature: GNU Guile integration + This version of GNU make can be compiled with GNU Guile integration. + GNU Guile serves as an embedded extension language for make. + See the "Guile Function" section in the GNU Make manual for details. + Currently GNU Guile 1.8 and 2.0+ are supported. In Guile 1.8 there is no + support for internationalized character sets. In Guile 2.0+, scripts can be + encoded in UTF-8. + +* New command line option: --output-sync (-O) enables grouping of output by + target or by recursive make. This is useful during parallel builds to avoid + mixing output from different jobs together giving hard-to-understand + results. Original implementation by David Boyce . + Reworked and enhanced by Frank Heckenbach . + Windows support by Eli Zaretskii . + +* New command line option: --trace enables tracing of targets. When enabled + the recipe to be invoked is printed even if it would otherwise be suppressed + by .SILENT or a "@" prefix character. Also before each recipe is run the + makefile name and linenumber where it was defined are shown as well as the + prerequisites that caused the target to be considered out of date. + +* New command line option argument: --debug now accepts a "n" (none) flag + which disables all debugging settings that are currently enabled. + +* New feature: The "job server" capability is now supported on Windows. + Implementation contributed by Troy Runkel + +* New feature: The .ONESHELL capability is now supported on Windows. Support + added by Eli Zaretskii . + +* New feature: "!=" shell assignment operator as an alternative to the + $(shell ...) function. Implemented for compatibility with BSD makefiles. + Note there are subtle differences between "!=" and $(shell ...). See the + description in the GNU make manual. + WARNING: Backward-incompatibility! + Variables ending in "!" previously defined as "variable!= value" will now be + interpreted as shell assignment. Change your assignment to add whitespace + between the "!" and "=": "variable! = value" + +* New feature: "::=" simple assignment operator as defined by POSIX in 2012. + This operator has identical functionality to ":=" in GNU make, but will be + portable to any implementation of make conforming to a sufficiently new + version of POSIX (see http://austingroupbugs.net/view.php?id=330). It is + not necessary to define the .POSIX target to access this operator. + +* New feature: Loadable objects + This version of GNU make contains a "technology preview": the ability to + load dynamic objects into the make runtime. These objects can be created by + the user and can add extended functionality, usable by makefiles. + +* New function: $(file ...) writes to a file. + +* New variable: $(GNUMAKEFLAGS) will be parsed for make flags, just like + MAKEFLAGS is. It can be set in the environment or the makefile, containing + GNU make-specific flags to allow your makefile to be portable to other + versions of make. Once this variable is parsed, GNU make will set it to the + empty string so that flags will not be duplicated on recursion. + +* New variable: `MAKE_HOST' gives the name of the host architecture + make was compiled for. This is the same value you see after 'Built for' + when running 'make --version'. + +* Behavior of MAKEFLAGS and MFLAGS is more rigorously defined. All simple + flags are grouped together in the first word of MAKEFLAGS. No options that + accept arguments appear in the first word. If no simple flags are present + MAKEFLAGS begins with a space. Flags with both short and long versions + always use the short versions in MAKEFLAGS. Flags are listed in + alphabetical order using ASCII ordering. MFLAGS never begins with "- ". + +* Setting the -r and -R options in MAKEFLAGS inside a makefile now works as + expected, removing all built-in rules and variables, respectively. + +* If a recipe fails, the makefile name and linenumber of the recipe are shown. + +* A .RECIPEPREFIX setting is remembered per-recipe and variables expanded + in that recipe also use that recipe prefix setting. + +* In -p output, .RECIPEPREFIX settings are shown and all target-specific + variables are output as if in a makefile, instead of as comments. + +* On MS-Windows, recipes that use ".." quoting will no longer force + invocation of commands via temporary batch files and stock Windows + shells, they will be short-circuited and invoked directly. (In + other words, " is no longer a special character for stock Windows + shells.) This avoids hitting shell limits for command length when + quotes are used, but nothing else in the command requires the shell. + This change could potentially mean some minor incompatibilities in + behavior when the recipe uses quoted string on shell command lines. + + +Version 3.82 (28 Jul 2010) + +A complete list of bugs fixed in this version is available here: + +http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=104&set=custom + +* Compiling GNU make now requires a conforming ISO C 1989 compiler and + standard runtime library. + +* WARNING: Backward-incompatibility! + The POSIX standard for make was changed in the 2008 version in a + fundamentally incompatible way: make is required to invoke the shell as if + the '-e' flag were provided. Because this would break many makefiles that + have been written to conform to the original text of the standard, the + default behavior of GNU make remains to invoke the shell with simply '-c'. + However, any makefile specifying the .POSIX special target will follow the + new POSIX standard and pass '-e' to the shell. See also .SHELLFLAGS + below. + +* WARNING: Backward-incompatibility! + The '$?' variable now contains all prerequisites that caused the target to + be considered out of date, even if they do not exist (previously only + existing targets were provided in $?). + +* WARNING: Backward-incompatibility! + Wildcards were not documented as returning sorted values, but the results + have been sorted up until this release.. If your makefiles require sorted + results from wildcard expansions, use the $(sort ...) function to request + it explicitly. + +* WARNING: Backward-incompatibility! + As a result of parser enhancements, three backward-compatibility issues + exist: first, a prerequisite containing an "=" cannot be escaped with a + backslash any longer. You must create a variable containing an "=" and + use that variable in the prerequisite. Second, variable names can no + longer contain whitespace, unless you put the whitespace in a variable and + use the variable. Third, in previous versions of make it was sometimes + not flagged as an error for explicit and pattern targets to appear in the + same rule. Now this is always reported as an error. + +* WARNING: Backward-incompatibility! + The pattern-specific variables and pattern rules are now applied in the + shortest stem first order instead of the definition order (variables + and rules with the same stem length are still applied in the definition + order). This produces the usually-desired behavior where more specific + patterns are preferred. To detect this feature search for 'shortest-stem' + in the .FEATURES special variable. + +* WARNING: Backward-incompatibility! + The library search behavior has changed to be compatible with the standard + linker behavior. Prior to this version for prerequisites specified using + the -lfoo syntax make first searched for libfoo.so in the current + directory, vpath directories, and system directories. If that didn't yield + a match, make then searched for libfoo.a in these directories. Starting + with this version make searches first for libfoo.so and then for libfoo.a + in each of these directories in order. + +* New command line option: --eval=STRING causes STRING to be evaluated as + makefile syntax (akin to using the $(eval ...) function). The evaluation + is performed after all default rules and variables are defined, but before + any makefiles are read. + +* New special variable: .RECIPEPREFIX allows you to reset the recipe + introduction character from the default (TAB) to something else. The + first character of this variable value is the new recipe introduction + character. If the variable is set to the empty string, TAB is used again. + It can be set and reset at will; recipes will use the value active when + they were first parsed. To detect this feature check the value of + $(.RECIPEPREFIX). + +* New special variable: .SHELLFLAGS allows you to change the options passed + to the shell when it invokes recipes. By default the value will be "-c" + (or "-ec" if .POSIX is set). + +* New special target: .ONESHELL instructs make to invoke a single instance + of the shell and provide it with the entire recipe, regardless of how many + lines it contains. As a special feature to allow more straightforward + conversion of makefiles to use .ONESHELL, any recipe line control + characters ('@', '+', or '-') will be removed from the second and + subsequent recipe lines. This happens _only_ if the SHELL value is deemed + to be a standard POSIX-style shell. If not, then no interior line control + characters are removed (as they may be part of the scripting language used + with the alternate SHELL). + +* New variable modifier 'private': prefixing a variable assignment with the + modifier 'private' suppresses inheritance of that variable by + prerequisites. This is most useful for target- and pattern-specific + variables. + +* New make directive: 'undefine' allows you to undefine a variable so that + it appears as if it was never set. Both $(flavor) and $(origin) functions + will return 'undefined' for such a variable. To detect this feature search + for 'undefine' in the .FEATURES special variable. + +* The parser for variable assignments has been enhanced to allow multiple + modifiers ('export', 'override', 'private') on the same line as variables, + including define/endef variables, and in any order. Also, it is possible + to create variables and targets named as these modifiers. + +* The 'define' make directive now allows a variable assignment operator + after the variable name, to allow for simple, conditional, or appending + multi-line variable assignment. + +* VMS-specific changes: + + * Michael Gehre (at VISTEC-SEMI dot COM) supplied a fix for a problem with + timestamps of object modules in OLBs. The timestamps were not correctly + adjusted to GMT based time, if the local VMS time was using a daylight + saving algorithm and if daylight saving was switched off. + + * John Eisenbraun (at HP dot COM) supplied fixes and and an enhancement to + append output redirection in action lines. + + * Rework of ctrl+c and ctrl+y handling. + + * Fix a problem with cached strings, which showed on case-insensitive file + systems. + + * Build fixes for const-ified code in VMS specific sources. + + * A note on appending the redirected output. With this change, a simple + mechanism is implemented to make ">>" work in action lines. In VMS + there is no simple feature like ">>" to have DCL command or program + output redirected and appended to a file. GNU make for VMS already + implements the redirection of output. If such a redirection is detected, + an ">" on the action line, GNU make creates a DCL command procedure to + execute the action and to redirect its output. Based on that, now ">>" + is also recognized and a similar but different command procedure is + created to implement the append. The main idea here is to create a + temporary file which collects the output and which is appended to the + wanted output file. Then the temporary file is deleted. This is all done + in the command procedure to keep changes in make small and simple. This + obviously has some limitations but it seems good enough compared with + the current ">" implementation. (And in my opinion, redirection is not + really what GNU make has to do.) With this approach, it may happen that + the temporary file is not yet appended and is left in SYS$SCRATCH. + The temporary file names look like "CMDxxxxx.". Any time the created + command procedure can not complete, this happens. Pressing Ctrl+Y to + abort make is one case. In case of Ctrl+Y the associated command + procedure is left in SYS$SCRATCH as well. Its name is CMDxxxxx.COM. + + * Change in the Ctrl+Y handling. The CtrlY handler now uses $delprc to + delete all children. This way also actions with DCL commands will be + stopped. As before the CtrlY handler then sends SIGQUIT to itself, + which is handled in common code. + + * Change in deleteing temporary command files. Temporary command files + are now deleted in the vms child termination handler. That deletes + them even if a Ctrl+C was pressed. + + * The behavior of pressing Ctrl+C is not changed. It still has only an + effect, after the current action is terminated. If that doesn't happen + or takes too long, Ctrl+Y should be used instead. + + +Version 3.81 (01 Apr 2006) + +* GNU make is ported to OS/2. + +* GNU make is ported to MinGW. The MinGW build is only supported by + the build_w32.bat batch file; see the file README.W32 for more + details. + +* WARNING: Future backward-incompatibility! + Up to and including this release, the '$?' variable does not contain + any prerequisite that does not exist, even though that prerequisite + might have caused the target to rebuild. Starting with the _next_ + release of GNU make, '$?' will contain all prerequisites that caused + the target to be considered out of date. + See http://savannah.gnu.org/bugs/?16051 + +* WARNING: Backward-incompatibility! + GNU make now implements a generic "second expansion" feature on the + prerequisites of both explicit and implicit (pattern) rules. In order + to enable this feature, the special target '.SECONDEXPANSION' must be + defined before the first target which takes advantage of it. If this + feature is enabled then after all rules have been parsed the + prerequisites are expanded again, this time with all the automatic + variables in scope. This means that in addition to using standard + SysV $$@ in prerequisites lists, you can also use complex functions + such as $$(notdir $$@) etc. This behavior applies to implicit rules, + as well, where the second expansion occurs when the rule is matched. + However, this means that when '.SECONDEXPANSION' is enabled you must + double-quote any "$" in your filenames; instead of "foo: boo$$bar" you + now must write "foo: foo$$$$bar". Note that the SysV $$@ etc. feature, + which used to be available by default, is now ONLY available when the + .SECONDEXPANSION target is defined. If your makefiles take advantage + of this SysV feature you will need to update them. + +* WARNING: Backward-incompatibility! + In order to comply with POSIX, the way in which GNU make processes + backslash-newline sequences in recipes has changed. If your makefiles + use backslash-newline sequences inside of single-quoted strings in + recipes you will be impacted by this change. See the GNU make manual + subsection "Splitting Recipe Lines" (node "Splitting Lines"), in + section "Recipe Syntax", chapter "Writing Recipe in Rules", for + details. + +* WARNING: Backward-incompatibility! + Some previous versions of GNU make had a bug where "#" in a function + invocation such as $(shell ...) was treated as a make comment. A + workaround was to escape these with backslashes. This bug has been + fixed: if your makefile uses "\#" in a function invocation the + backslash is now preserved, so you'll need to remove it. + +* New command line option: -L (--check-symlink-times). On systems that + support symbolic links, if this option is given then GNU make will + use the most recent modification time of any symbolic links that are + used to resolve target files. The default behavior remains as it + always has: use the modification time of the actual target file only. + +* The "else" conditional line can now be followed by any other valid + conditional on the same line: this does not increase the depth of the + conditional nesting, so only one "endif" is required to close the + conditional. + +* All pattern-specific variables that match a given target are now used + (previously only the first match was used). + +* Target-specific variables can be marked as exportable using the + "export" keyword. + +* In a recursive $(call ...) context, any extra arguments from the outer + call are now masked in the context of the inner call. + +* Implemented a solution for the "thundering herd" problem with "-j -l". + This version of GNU make uses an algorithm suggested by Thomas Riedl + to track the number of jobs started in the + last second and artificially adjust GNU make's view of the system's + load average accordingly. + +* New special variables available in this release: + - .INCLUDE_DIRS: Expands to a list of directories that make searches + for included makefiles. + - .FEATURES: Contains a list of special features available in this + version of GNU make. + - .DEFAULT_GOAL: Set the name of the default goal make will + use if no goals are provided on the command line. + - MAKE_RESTARTS: If set, then this is the number of times this + instance of make has been restarted (see "How Makefiles Are Remade" + in the manual). + - New automatic variable: $| (added in 3.80, actually): contains all + the order-only prerequisites defined for the target. + +* New functions available in this release: + - $(lastword ...) returns the last word in the list. This gives + identical results as $(word $(words ...) ...), but is much faster. + - $(abspath ...) returns the absolute path (all "." and ".." + directories resolved, and any duplicate "/" characters removed) for + each path provided. + - $(realpath ...) returns the canonical pathname for each path + provided. The canonical pathname is the absolute pathname, with + all symbolic links resolved as well. + - $(info ...) prints its arguments to stdout. No makefile name or + line number info, etc. is printed. + - $(flavor ...) returns the flavor of a variable. + - $(or ...) provides a short-circuiting OR conditional: each argument + is expanded. The first true (non-empty) argument is returned; no + further arguments are expanded. Expands to empty if there are no + true arguments. + - $(and ...) provides a short-circuiting AND conditional: each + argument is expanded. The first false (empty) argument is + returned; no further arguments are expanded. Expands to the last + argument if all arguments are true. + +* Changes made for POSIX compatibility: + - Only touch targets (under -t) if they have a recipe. + - Setting the SHELL make variable does NOT change the value of the + SHELL environment variable given to programs invoked by make. As + an enhancement to POSIX, if you export the make variable SHELL then + it will be set in the environment, just as before. + +* On MS Windows systems, explicitly setting SHELL to a pathname ending + in "cmd" or "cmd.exe" (case-insensitive) will force GNU make to use + the DOS command interpreter in batch mode even if a UNIX-like shell + could be found on the system. + +* On VMS there is now support for case-sensitive filesystems such as ODS5. + See the README.VMS file for information. + +* Parallel builds (-jN) no longer require a working Bourne shell on + Windows platforms. They work even with the stock Windows shells, such + as cmd.exe and command.com. + +* Updated to autoconf 2.59, automake 1.9.5, and gettext 0.14.1. Users + should not be impacted. + +* New translations for Swedish, Chinese (simplified), Ukrainian, + Belarusian, Finnish, Kinyarwandan, and Irish. Many updated + translations. + +A complete list of bugs fixed in this version is available here: + + http://savannah.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=103 + + +Version 3.80 (03 Oct 2002) + +* A new feature exists: order-only prerequisites. These prerequisites + affect the order in which targets are built, but they do not impact + the rebuild/no-rebuild decision of their dependents. That is to say, + they allow you to require target B be built before target A, without + requiring that target A will always be rebuilt if target B is updated. + Patch for this feature provided by Greg McGary . + +* For compatibility with SysV make, GNU make now supports the peculiar + syntax $$@, $$(@D), and $$(@F) in the prerequisites list of a rule. + This syntax is only valid within explicit and static pattern rules: it + cannot be used in implicit (suffix or pattern) rules. Edouard G. Parmelan + provided a patch implementing this feature; however, I + decided to implement it in a different way. + +* The argument to the "ifdef" conditional is now expanded before it's + tested, so it can be a constructed variable name. + + Similarly, the arguments to "export" (when not used in a variable + definition context) and "unexport" are also now expanded. + +* A new function is defined: $(value ...). The argument to this + function is the _name_ of a variable. The result of the function is + the value of the variable, without having been expanded. + +* A new function is defined: $(eval ...). The arguments to this + function should expand to makefile commands, which will then be + evaluated as if they had appeared in the makefile. In combination + with define/endef multiline variable definitions this is an extremely + powerful capability. The $(value ...) function is also sometimes + useful here. + +* A new built-in variable is defined, $(MAKEFILE_LIST). It contains a + list of each makefile GNU make has read, or started to read, in the + order in which they were encountered. So, the last filename in the + list when a makefile is just being read (before any includes) is the + name of the current makefile. + +* A new built-in variable is defined: $(.VARIABLES). When it is + expanded it returns a complete list of variable names defined by all + makefiles at that moment. + +* A new command line option is defined, -B or --always-make. If + specified GNU make will consider all targets out-of-date even if they + would otherwise not be. + +* The arguments to $(call ...) functions were being stored in $1, $2, + etc. as recursive variables, even though they are fully expanded + before assignment. This means that escaped dollar signs ($$ etc.) + were not behaving properly. Now the arguments are stored as simple + variables. This may mean that if you added extra escaping to your + $(call ...) function arguments you will need to undo it now. + +* The variable invoked by $(call ...) can now be recursive: unlike other + variables it can reference itself and this will not produce an error + when it is used as the first argument to $(call ...) (but only then). + +* New pseudo-target .LOW_RESOLUTION_TIME, superseding the configure + option --disable-nsec-timestamps. You might need this if your build + process depends on tools like "cp -p" preserving time stamps, since + "cp -p" (right now) doesn't preserve the subsecond portion of a time + stamp. + +* Updated translations for French, Galician, German, Japanese, Korean, + and Russian. New translations for Croatian, Danish, Hebrew, and + Turkish. + +* Updated internationalization support to Gettext 0.11.5. + GNU make now uses Gettext's "external" feature, and does not include + any internationalization code itself. Configure will search your + system for an existing implementation of GNU Gettext (only GNU Gettext + is acceptable) and use it if it exists. If not, NLS will be disabled. + See ABOUT-NLS for more information. + +* Updated to autoconf 2.54 and automake 1.7. Users should not be impacted. + +* VMS-specific changes: + + * In default.c define variable ARCH as IA64 for VMS on Itanium systems. + + * In makefile.vms avoid name collision for glob and globfree. + + * This is the VMS port of GNU Make done by Hartmut.Becker@compaq.com. + + It is based on the specific version 3.77k and on 3.78.1. 3.77k was done + by Klaus Kämpf , the code was based on the VMS port of + GNU Make 3.60 by Mike Moretti. + + It was ported on OpenVMS/Alpha V7.1, DECC V5.7-006. It was re-build and + tested on OpenVMS/Alpha V7.2, OpenVMS/VAX 7.1 and 5.5-2. Different + versions of DECC were used. VAXC was tried: it fails; but it doesn't + seem worth to get it working. There are still some PTRMISMATCH warnings + during the compile. Although perl is working on VMS the test scripts + don't work. The function $shell is still missing. + + There is a known bug in some of the VMS CRTLs. It is in the shipped + versions of VMS V7.2 and V7.2-1 and in the currently (October 1999) + available ECOs for VMS V7.1 and newer versions. It is fixed in versions + shipped with newer VMS versions and all ECO kits after October 1999. It + only shows up during the daylight saving time period (DST): stat() + returns a modification time 1 hour ahead. This results in GNU make + warning messages. For a just created source you will see: + + $ gmake x.exe + gmake.exe;1: *** Warning: File 'x.c' has modification time in the future + (940582863 > 940579269) + cc /obj=x.obj x.c + link x.obj /exe=x.exe + gmake.exe;1: *** Warning: Clock skew detected. Your build may be + incomplete. + + +A complete list of bugs fixed in this version is available here: + + http://savannah.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=102 + + +Version 3.79.1 (23 Jun 2000) + +* .SECONDARY with no prerequisites now prevents any target from being + removed because make thinks it's an intermediate file, not just those + listed in the makefile. + +* New configure option --disable-nsec-timestamps, but this was + superseded in later versions by the .LOW_RESOLUTION_TIME pseudo-target. + +Version 3.79 (04 Apr 2000) + +* GNU make optionally supports internationalization and locales via the + GNU gettext (or local gettext if suitable) package. See the ABOUT-NLS + file for more information on configuring GNU make for NLS. + +* Previously, GNU make quoted variables such as MAKEFLAGS and + MAKEOVERRIDES for proper parsing by the shell. This allowed them to + be used within make build scripts. However, using them there is not + proper behavior: they are meant to be passed to subshells via the + environment. Unfortunately the values were not quoted properly to be + passed through the environment. This meant that make didn't properly + pass some types of command line values to submakes. + + With this version we change that behavior: now these variables are + quoted properly for passing through the environment, which is the + correct way to do it. If you previously used these variables + explicitly within a make rule you may need to re-examine your use for + correctness given this change. + +* A new pseudo-target .NOTPARALLEL is available. If defined, the + current makefile is run serially regardless of the value of -j. + However, submakes are still eligible for parallel execution. + +* The --debug option has changed: it now allows optional flags + controlling the amount and type of debugging output. By default only + a minimal amount information is generated, displaying the names of + "normal" targets (not makefiles) that were deemed out of date and in + need of being rebuilt. + + Note that the -d option behaves as before: it takes no arguments and + all debugging information is generated. + +* The `-p' (print database) output now includes filename and linenumber + information for variable definitions, to aid debugging. + +* The wordlist function no longer reverses its arguments if the "start" + value is greater than the "end" value. If that's true, nothing is + returned. + +* Hartmut Becker provided many updates for the VMS port of GNU make. + See the README.VMS file for more details. + +* VMS-specific changes: + + * Fix a problem with automatically remaking makefiles. GNU make uses an + execve to restart itself after a successful remake of the makefile. On + UNIX systems execve replaces the running program with a new one and + resets all signal handling to the default. On VMS execve creates a child + process, signal and exit handlers of the parent are still active, and, + unfortunately, corrupt the exit code from the child. Fix in job.c: + ignore SIGCHLD. + + * Added some switches to reflect latest features of DECC. Modifications in + makefile.vms. + + * Set some definitions to reflect latest features of DECC. Modifications in + config.h-vms (which is copied to config.h). + + * Added extern strcmpi declaration to avoid 'implicitly declared' messages. + Modification in make.h. + + * Default rule for C++, conditionals for gcc (GCC_IS_NATIVE) or DEC/Digital/ + Compaq c/c++ compilers. Modifications in default.c. + + * Usage of opendir() and friends, suppress file version. Modifications in + dir.c. + + * Added VMS specific code to handle ctrl+c and ctrl+y to abort make. + Modifications in job.c. + + * Added support to have case sensitive targets and dependencies but to + still use case blind file names. This is especially useful for Java + makefiles on VMS: + + .SUFFIXES : + .SUFFIXES : .class .java + .java.class : + javac "$< + HelloWorld.class : HelloWorld.java + + * A new macro WANT_CASE_SENSITIVE_TARGETS in config.h-vms was introduced. + It needs to be enabled to get this feature; default is disabled. The + macro HAVE_CASE_INSENSITIVE_FS must not be touched: it is still enabled. + Modifications in file.c and config.h-vms. + + * Bootstrap make to start building make is still makefile.com, but make + needs to be re-made with a make to make a correct version: ignore all + possible warnings, delete all objects, rename make.exe to a different + name and run it. + + * Made some minor modifications to the bootstrap build makefile.com. + +Version 3.78 (22 Sep 1999) + +* Two new functions, $(error ...) and $(warning ...) are available. The + former will cause make to fail and exit immediately upon expansion of + the function, with the text provided as the error message. The latter + causes the text provided to be printed as a warning message, but make + proceeds normally. + +* A new function $(call ...) is available. This allows users to create + their own parameterized macros and invoke them later. Original + implementation of this function was provided by Han-Wen Nienhuys + . + +* A new function $(if ...) is available. It provides if-then-else + capabilities in a builtin function. Original implementation of this + function was provided by Han-Wen Nienhuys . + +* Make defines a new variable, .LIBPATTERNS. This variable controls how + library dependency expansion (dependencies like ``-lfoo'') is performed. + +* Make accepts CRLF sequences as well as traditional LF, for + compatibility with makefiles created on other operating systems. + +* Make accepts a new option: -R, or --no-builtin-variables. This option + disables the definition of the rule-specific builtin variables (CC, + LD, AR, etc.). Specifying this option forces -r (--no-builtin-rules) + as well. + +* A "job server" feature, suggested by Howard Chu . + + On systems that support POSIX pipe(2) semantics, GNU make can now pass + -jN options to submakes rather than forcing them all to use -j1. The + top make and all its sub-make processes use a pipe to communicate with + each other to ensure that no more than N jobs are started across all + makes. To get the old behavior of -j back, you can configure make + with the --disable-job-server option. + +* The confusing term "dependency" has been replaced by the more accurate + and standard term "prerequisite", both in the manual and in all GNU make + output. + +* GNU make supports the "big archive" library format introduced in AIX 4.3. + +* GNU make supports large files on AIX, HP-UX, and IRIX. These changes + were provided by Paul Eggert . (Large file + support for Solaris and Linux was introduced in 3.77, but the + configuration had issues: these have also been resolved). + +* The Windows 95/98/NT (W32) version of GNU make now has native support + for the Cygnus Cygwin release B20.1 shell (bash). + +* The GNU make regression test suite, long available separately "under + the table", has been integrated into the release. You can invoke it + by running "make check" in the distribution. Note that it requires + Perl (either Perl 4 or Perl 5) to run. + +Version 3.77 (28 Jul 1998) + +* Implement BSD make's "?=" variable assignment operator. The variable + is assigned the specified value only if that variable is not already + defined. + +* Make defines a new variable, "CURDIR", to contain the current working + directory (after the -C option, if any, has been processed). + Modifying this variable has no effect on the operation of make. + +* Make defines a new default RCS rule, for new-style master file + storage: ``% :: RCS/%'' (note no ``,v'' suffix). + + Make defines new default rules for DOS-style C++ file naming + conventions, with ``.cpp'' suffixes. All the same rules as for + ``.cc'' and ``.C'' suffixes are provided, along with LINK.cpp and + COMPILE.cpp macros (which default to the same value as LINK.cc and + COMPILE.cc). Note CPPFLAGS is still C preprocessor flags! You should + use CXXFLAGS to change C++ compiler flags. + +* A new feature, "target-specific variable values", has been added. + This is a large change so please see the appropriate sections of the + manual for full details. Briefly, syntax like this: + + TARGET: VARIABLE = VALUE + + defines VARIABLE as VALUE within the context of TARGET. This is + similar to SunOS make's "TARGET := VARIABLE = VALUE" feature. Note + that the assignment may be of any type, not just recursive, and that + the override keyword is available. + + COMPATIBILITY: This new syntax means that if you have any rules where + the first or second dependency has an equal sign (=) in its name, + you'll have to escape them with a backslash: "foo : bar\=baz". + Further, if you have any dependencies which already contain "\=", + you'll have to escape both of them: "foo : bar\\\=baz". + +* A new appendix listing the most common error and warning messages + generated by GNU make, with some explanation, has been added to the + GNU make User's Manual. + +* Updates to the GNU make Customs library support (see README.customs). + +* Updates to the Windows 95/NT port from Rob Tulloh (see README.W32), + and to the DOS port from Eli Zaretski (see README.DOS). + +* VMS-specific changes: + + * This is the VMS port of GNU Make. + It is based on the VMS port of GNU Make 3.60 by Mike Moretti. + This port was done by Klaus Kämpf + + * There is first-level support available from proGIS Software, Germany. + Visit their web-site at http://www.progis.de to get information + about other vms software and forthcoming updates to gnu make. + + * /bin/sh style I/O redirection is supported. You can now write lines like + mcr sys$disk:[]program.exe < input.txt > output.txt &> error.txt + + * Makefile variables are looked up in the current environment. You can set + symbols or logicals in DCL and evaluate them in the Makefile via + $(). Variables defined in the Makefile + override VMS symbols/logicals ! + + * Functions for file names are working now. See the GNU Make manual for + $(dir ...) and $(wildcard ...). Unix-style and VMS-style names are + supported as arguments. + + * The default rules are set up for GNU C. Building an executable from a + single source file is as easy as 'make file.exe'. + + * The variable $(ARCH) is predefined as ALPHA or VAX resp. Makefiles for + different VMS systems can now be written by checking $(ARCH) as in + ifeq ($(ARCH),ALPHA) + $(ECHO) "On the Alpha" + else + $(ECHO) "On the VAX" + endif + + * Command lines of excessive length are correctly broken and written to a + batch file in sys$scratch for later execution. There's no limit to the + lengths of commands (and no need for .opt files :-) any more. + + * Empty commands are handled correctly and don't end in a new DCL process. + +Version 3.76.1 (19 Sep 1997) + +* Small (but serious) bug fix. Quick rollout to get into the GNU source CD. + +Version 3.76 (16 Sep 1997) + +* GNU make now uses automake to control Makefile.in generation. This + should make it more consistent with the GNU standards. + +* VPATH functionality has been changed to incorporate the VPATH+ patch, + previously maintained by Paul Smith . See the + manual. + +* Make defines a new variable, `MAKECMDGOALS', to contain the goals that + were specified on the command line, if any. Modifying this variable + has no effect on the operation of make. + +* A new function, `$(wordlist S,E,TEXT)', is available: it returns a + list of words from number S to number E (inclusive) of TEXT. + +* Instead of an error, detection of future modification times gives a + warning and continues. The warning is repeated just before GNU make + exits, so it is less likely to be lost. + +* Fix the $(basename) and $(suffix) functions so they only operate on + the last filename, not the entire string: + + Command Old Result New Result + ------- ---------- ---------- + $(basename a.b) a a + $(basename a.b/c) a a.b/c + $(suffix a.b) b b + $(suffix a.b/c) b/c + +* The $(strip) function now removes newlines as well as TABs and spaces. + +* The $(shell) function now changes CRLF (\r\n) pairs to a space as well + as newlines (\n). + +* Updates to the Windows 95/NT port from Rob Tulloh (see README.W32). + +* Eli Zaretskii has updated the port to 32-bit protected mode on MSDOS + and MS-Windows, building with the DJGPP v2 port of GNU C/C++ compiler + and utilities. See README.DOS for details, and direct all questions + concerning this port to Eli Zaretskii or DJ + Delorie . + +* VMS-specific changes: + + * John W. Eaton has updated the VMS port to support libraries and VPATH. + + * The cd command is supported if it's called as $(CD). This invokes + the 'builtin_cd' command which changes the directory. + Calling 'set def' doesn't do the trick, since a sub-shell is + spawned for this command, the directory is changed *in this sub-shell* + and the sub-shell ends. + + * Libraries are not supported. They were in GNU Make 3.60 but somehow I + didn't care porting the code. If there is enough interest, I'll do it at + some later time. + + * The variable $^ separates files with commas instead of spaces (It's the + natural thing to do for VMS). + + * See defaults.c for VMS default suffixes and my definitions for default + rules and variables. + + * The shell function is not implemented yet. + + * Load average routines haven't been implemented for VMS yet. + + * The default include directory for including other makefiles is + SYS$SYSROOT:[SYSLIB] (I don't remember why I didn't just use + SYS$LIBRARY: instead; maybe it wouldn't work that way). + + * The default makefiles make looks for are: makefile.vms, gnumakefile, + makefile., and gnumakefile. . + + * The stat() function and handling of time stamps in VMS is broken, so I + replaced it with a hack in vmsfunctions.c. I will provide a full rewrite + somewhere in the future. Be warned, the time resolution inside make is + less than what vms provides. This might be a problem on the faster Alphas. + + * You can use a : in a filename only if you precede it with a backslash ('\'). + E.g.- hobbes\:[bogas.files] + + * Make ignores success, informational, or warning errors (-S-, -I-, or -W-). + But it will stop on -E- and -F- errors. (unless you do something + to override this in your makefile, or whatever). + + * Remote stuff isn't implemented yet. + + * Multiple line DCL commands, such as "if" statements, must be put inside + command files. You can run a command file by using \@. + +Version 3.75 (27 Aug 1996) + +* The directory messages printed by `-w' and implicitly in sub-makes, + are now omitted if Make runs no commands and has no other messages to print. + +* Make now detects files that for whatever reason have modification times + in the future and gives an error. Files with such impossible timestamps + can result from unsynchronized clocks, or archived distributions + containing bogus timestamps; they confuse Make's dependency engine + thoroughly. + +* The new directive `sinclude' is now recognized as another name for + `-include', for compatibility with some other Makes. + +* Aaron Digulla has contributed a port to AmigaDOS. See README.Amiga for + details, and direct all Amiga-related questions to . + +* Rob Tulloh of Tivoli Systems has contributed a port to Windows NT or 95. + See README.W32 for details, and direct all Windows-related questions to + . + +* VMS-specific changes: + + * Lots of default settings are adapted for VMS. See default.c. + + * Long command lines are now converted to command files. + + * Comma (',') as a separator is now allowed. See makefile.vms for an example. + +Version 3.73 (05 Apr 1995) + +* Converted to use Autoconf version 2, so `configure' has some new options. + See INSTALL for details. + +* You can now send a SIGUSR1 signal to Make to toggle printing of debugging + output enabled by -d, at any time during the run. + +Version 3.72 (04 Nov 1994) + +* DJ Delorie has ported Make to MS-DOS using the GO32 extender. + He is maintaining the DOS port, not the GNU Make maintainer; + please direct bugs and questions for DOS to . + MS-DOS binaries are available for FTP from ftp.simtel.net in + /pub/simtelnet/gnu/djgpp/. + +* The `MAKEFLAGS' variable (in the environment or in a makefile) can now + contain variable definitions itself; these are treated just like + command line variable definitions. Make will automatically insert any + variable definitions from the environment value of `MAKEFLAGS' or from + the command line, into the `MAKEFLAGS' value exported to children. The + `MAKEOVERRIDES' variable previously included in the value of `$(MAKE)' + for sub-makes is now included in `MAKEFLAGS' instead. As before, you can + reset `MAKEOVERRIDES' in your makefile to avoid putting all the variables + in the environment when its size is limited. + +* If `.DELETE_ON_ERROR' appears as a target, Make will delete the target of + a rule if it has changed when its recipe exits with a nonzero status, + just as when the recipe gets a signal. + +* The automatic variable `$+' is new. It lists all the dependencies like + `$^', but preserves duplicates listed in the makefile. This is useful + for linking rules, where library files sometimes need to be listed twice + in the link order. + +* You can now specify the `.IGNORE' and `.SILENT' special targets with + dependencies to limit their effects to those files. If a file appears as + a dependency of `.IGNORE', then errors will be ignored while running the + recipe to update that file. Likewise if a file appears as a dependency + of `.SILENT', then the recipe to update that file will not be printed + before it is run. (This change was made to conform to POSIX.2.) + +Version 3.71 (21 May 1994) + +* The automatic variables `$(@D)', `$(%D)', `$(*D)', `$(. diff --git a/src/kmk/NMakefile.template b/src/kmk/NMakefile.template new file mode 100644 index 0000000..2007a3b --- /dev/null +++ b/src/kmk/NMakefile.template @@ -0,0 +1,132 @@ +# -*-Makefile-*- to build GNU make with nmake +# +# NOTE: If you have no 'make' program at all to process this makefile, +# run 'build_w32.bat' instead. +# +# Copyright (C) 1996-2016 Free Software Foundation, Inc. +# This file is part of GNU Make. +# +# GNU Make is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +LINK = link +CC = cl +MAKE = nmake + +OUTDIR=. +MAKEFILE=NMakefile +SUBPROC_MAKEFILE=NMakefile + +CFLAGS_any = /nologo /MT /W4 /GX /Zi /YX /I . /I glob /I w32/include /D WIN32 /D WINDOWS32 /D _CONSOLE /D HAVE_CONFIG_H +CFLAGS_debug = $(CFLAGS_any) /Od /D DEBUG /D _DEBUG /FR.\WinDebug/ /Fp.\WinDebug/make.pch /Fo.\WinDebug/ /Fd.\WinDebug/make.pdb +CFLAGS_release = $(CFLAGS_any) /O2 /D NDEBUG /FR.\WinRel/ /Fp.\WinRel/make.pch /Fo.\WinRel/ + +LDFLAGS_debug = w32\subproc\WinDebug\subproc.lib /NOLOGO /SUBSYSTEM:console\ + /STACK:0x400000 /INCREMENTAL:no /PDB:WinDebug/make.pdb /OUT:WinDebug/make.exe /DEBUG +LDFLAGS_release = w32\subproc\WinRel\subproc.lib /NOLOGO /SUBSYSTEM:console\ + /STACK:0x400000 /INCREMENTAL:no /OUT:WinRel/make.exe + +all: config.h subproc Release Debug + +# +# Make sure we build the subproc library first. It has it's own +# makefile. To be portable to Windows 95, we put the instructions +# on how to build the library into a batch file. On NT, we could +# simply have done foo && bar && dog, but this doesn't port. +# +subproc: w32/subproc/WinDebug/subproc.lib w32/subproc/WinRel/subproc.lib + +w32/subproc/WinDebug/subproc.lib w32/subproc/WinRel/subproc.lib: w32/subproc/misc.c w32/subproc/sub_proc.c w32/subproc/w32err.c + subproc.bat $(SUBPROC_MAKEFILE) $(MAKE) + if exist WinDebug\make.exe erase WinDebug\make.exe + if exist WinRel\make.exe erase WinRel\make.exe + +config.h: config.h.W32 + copy $? $@ + +Release: + $(MAKE) /f $(MAKEFILE) LDFLAGS="$(LDFLAGS_release)" CFLAGS="$(CFLAGS_release)" OUTDIR=WinRel WinRel/make.exe +Debug: + $(MAKE) /f $(MAKEFILE) LDFLAGS="$(LDFLAGS_debug)" CFLAGS="$(CFLAGS_debug)" OUTDIR=WinDebug WinDebug/make.exe + +clean: + if exist WinDebug\nul rmdir /s /q WinDebug + if exist WinRel\nul rmdir /s /q WinRel + if exist w32\subproc\WinDebug\nul rmdir /s /q w32\subproc\WinDebug + if exist w32\subproc\WinRel\nul rmdir /s /q w32\subproc\WinRel + if exist config.h erase config.h + erase *.pdb + +$(OUTDIR): + if not exist .\$@\nul mkdir .\$@ + +LIBS = kernel32.lib user32.lib advapi32.lib + +guile = $(OUTDIR)/guile.obj + +OBJS = \ + $(OUTDIR)/ar.obj \ + $(OUTDIR)/arscan.obj \ + $(OUTDIR)/commands.obj \ + $(OUTDIR)/default.obj \ + $(OUTDIR)/dir.obj \ + $(OUTDIR)/expand.obj \ + $(OUTDIR)/file.obj \ + $(OUTDIR)/function.obj \ + $(OUTDIR)/getloadavg.obj \ + $(OUTDIR)/getopt.obj \ + $(OUTDIR)/getopt1.obj \ + $(OUTDIR)/hash.obj \ + $(OUTDIR)/implicit.obj \ + $(OUTDIR)/job.obj \ + $(OUTDIR)/load.obj \ + $(OUTDIR)/main.obj \ + $(OUTDIR)/misc.obj \ + $(OUTDIR)/output.obj \ + $(OUTDIR)/read.obj \ + $(OUTDIR)/remake.obj \ + $(OUTDIR)/remote-stub.obj \ + $(OUTDIR)/rule.obj \ + $(OUTDIR)/signame.obj \ + $(OUTDIR)/strcache.obj \ + $(OUTDIR)/variable.obj \ + $(OUTDIR)/version.obj \ + $(OUTDIR)/vpath.obj \ + $(OUTDIR)/glob.obj \ + $(OUTDIR)/fnmatch.obj \ + $(OUTDIR)/dirent.obj \ + $(OUTDIR)/pathstuff.obj \ + $(OUTDIR)/posixfcn.obj \ + $(OUTDIR)/w32os.obj \ + $(guile) + +$(OUTDIR)/make.exe: $(OUTDIR) $(OBJS) + $(LINK) @<< + $(LDFLAGS) $(LIBS) $(OBJS) +<< + +.c{$(OUTDIR)}.obj: + $(CC) $(CFLAGS) /c $< + +$(OUTDIR)/glob.obj : glob/glob.c + $(CC) $(CFLAGS) /c $? +$(OUTDIR)/fnmatch.obj : glob/fnmatch.c + $(CC) $(CFLAGS) /c $? +$(OUTDIR)/dirent.obj : w32/compat/dirent.c + $(CC) $(CFLAGS) /c $? +$(OUTDIR)/posixfcn.obj : w32/compat/posixfcn.c + $(CC) $(CFLAGS) /c $? +$(OUTDIR)/pathstuff.obj : w32/pathstuff.c + $(CC) $(CFLAGS) /c $? +$(OUTDIR)/w32os.obj : w32/w32os.c + $(CC) $(CFLAGS) /c $? diff --git a/src/kmk/README.Amiga b/src/kmk/README.Amiga new file mode 100644 index 0000000..68d3ea7 --- /dev/null +++ b/src/kmk/README.Amiga @@ -0,0 +1,77 @@ +Short: Port of GNU make with SAS/C (no ixemul.library required) +Author: GNU, Amiga port by Aaron "Optimizer" Digulla +Uploader: Aaron "Optimizer" Digulla (digulla@fh-konstanz.de) +Type: dev/c + +This is a pure Amiga port of GNU make. It needs no extra libraries or +anything. It has the following features (in addition to any features of +GNU make): + +- Runs Amiga-Commands with SystemTags() (Execute) +- Can run multi-line statements +- Allows to use Device-Names in targets: + + c:make : make.o + + is ok. To distinguish between device-names and target : or ::, MAKE + looks for spaces. If there are any around :, it's taken as a target + delimiter, if there are none, it's taken as the name of a device. Note + that "make:make.o" tries to create "make.o" on the device "make:". +- Replaces @@ by a newline in any command line: + + if exists make @@\ + delete make.bak quiet @@\ + rename make make.bak @@\ + endif @@\ + $(CC) Link Make.o To make + + works. Note that the @@ must stand alone (i.e., "make@@\" is illegal). + Also be careful that there is a space after the "\" (i.e., at the + beginning of the next line). +- Can be made resident to save space and time +- Amiga specific wildcards can be used in $(wildcard ...) + +BUGS: +- The line + + dummy.h : src/*.c + +tries to make dummy.h from "src/*.c" (i.e., no wildcard-expansion takes +place). You have to use "$(wildcard src/*.c)" instead. + +COMPILING FROM SCRATCH +---------------------- + +To recompile, you need SAS/C 6.51. make itself is not necessary, there +is an smakefile. + +1. Copy config.ami to config.h +2. If you use make to compile, copy Makefile.ami to Makefile and + glob/Makefile.ami to glob/Makefile. Copy make into the current + directory. + +3. Run smake/make + +INSTALLATION + +Copy make somewhere in your search path (e.g., sc:c or sc:bin). +If you plan to use recursive makes, install make resident: + + Resident make Add + + +------------------------------------------------------------------------------- +Copyright (C) 1995-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . diff --git a/src/kmk/README.DOS.template b/src/kmk/README.DOS.template new file mode 100644 index 0000000..bc31adb --- /dev/null +++ b/src/kmk/README.DOS.template @@ -0,0 +1,340 @@ +Port of GNU Make to 32-bit protected mode on MSDOS and MS-Windows. + +Builds with DJGPP v2 port of GNU C/C++ compiler and utilities. + + +New (since 3.74) DOS-specific features: + + 1. Supports long filenames when run from DOS box on Windows 9x. + + 2. Supports both stock DOS COMMAND.COM and Unix-style shells + (details in 'Notes' below). + + 3. Supports DOS drive letters in dependencies and pattern rules. + + 4. Better support for DOS-style backslashes in pathnames (but see + 'Notes' below). + + 5. The $(shell) built-in can run arbitrary complex commands, + including pipes and redirection, even when COMMAND.COM is your + shell. + + 6. Can be built without floating-point code (see below). + + 7. Supports signals in child programs and restores the original + directory if the child was interrupted. + + 8. Can be built without (a previous version of) Make. + + 9. The build process requires only standard tools. (Optional + targets like "install:" and "clean:" still need additional + programs, though, see below.) + + 10. Beginning with v3.78, the test suite works in the DJGPP + environment (requires Perl and auxiliary tools; see below). + + +To install a binary distribution: + + Simply unzip the makNNNb.zip file (where NNN is the version number) + preserving the directory structure (-d switch if you use PKUNZIP). + If you are installing Make on Windows 9X or Windows 2000, use an + unzip program that supports long filenames in zip files. After + unzipping, make sure the directory with make.exe is on your PATH, + and that's all you need to use Make. + + +To build from sources: + + 1. Unzip the archive, preserving the directory structure (-d switch + if you use PKUNZIP). If you build Make on Windows 9X or Windows + 2000, use an unzip program that supports long filenames in zip + files. + + If you are unpacking an official GNU source distribution, use + either DJTAR (which is part of the DJGPP development + environment), or the DJGPP port of GNU Tar. + + 2. Invoke the 'configure.bat' batch file. + + If you are building Make in-place, i.e. in the same directory + where its sources are kept, just type "configure.bat" and press + [Enter]. Otherwise, you need to supply the path to the source + directory as an argument to the batch file, like this: + + c:\djgpp\gnu\make-%VERSION%\configure.bat c:/djgpp/gnu/make-%VERSION% + + Note the forward slashes in the source path argument: you MUST + use them here. + + 3. If configure.bat doesn't find a working Make, it will suggest to + use the 'dosbuild.bat' batch file to build Make. Either do as it + suggests or install another Make program (a pre-compiled binary + should be available from the usual DJGPP sites) and rerun + configure.bat. + + 4. If you will need to run Make on machines without an FPU, you + might consider building a version of Make which doesn't issue + floating-point instructions (they don't help much on MSDOS + anyway). To this end, edit the Makefile created by + configure.bat and add -DNO_FLOAT to the value of CPPFLAGS. + + 5. Invoke Make. + + If you are building from outside of the source directory, you + need to tell Make where the sources are, like this: + + make srcdir=c:/djgpp/gnu/make-%VERSION% + + (configure.bat will tell you this when it finishes). You MUST + use a full, not relative, name of the source directory here, or + else Make might fail. + + 6. After Make finishes, if you have a Unix-style shell installed, + you can use the 'install' target to install the package. You + will also need GNU Fileutils and GNU Sed for this (they should + be available from the DJGPP sites). + + By default, GNU make will install into your DJGPP installation + area. If you wish to use a different directory, override the + DESTDIR variable when invoking "make install", like this: + + make install DESTDIR=c:/other/dir + + This causes the make executable to be placed in c:/other/dir/bin, + the man pages in c:/other/dir/man, etc. + + Without a Unix-style shell, you will have to install programs + and the docs manually. Copy make.exe to a directory on your + PATH, make.i* info files to your Info directory, and update the + file 'dir' in your Info directory by adding the following item + to the main menu: + + * Make: (make.info). The GNU make utility. + + If you have the 'install-info' program (from the GNU Texinfo + package), it will do that for you if you invoke it like this: + + install-info --info-dir=c:/djgpp/info c:/djgpp/info/make.info + + (If your Info directory is other than C:\DJGPP\INFO, change this + command accordingly.) + + 7. The 'clean' targets also require Unix-style shell, and GNU Sed + and 'rm' programs (the latter from Fileutils). + + 8. To run the test suite, type "make check". This requires a Unix + shell (I used the DJGPP port of Bash 2.03), Perl, Sed, Fileutils + and Sh-utils. + + +Notes: +----- + + 1. The shell issue. + + This is probably the most significant improvement, first + introduced in the port of GNU Make 3.75. + + The original behavior of GNU Make is to invoke commands + directly, as long as they don't include characters special to + the shell or internal shell commands, because that is faster. + When shell features like redirection or filename wildcards are + involved, Make calls the shell. + + This port supports both DOS shells (the stock COMMAND.COM and its + 4DOS/NDOS replacements), and Unix-style shells (tested with the + venerable Stewartson's 'ms_sh' 2.3 and the DJGPP port of 'bash' by + Daisuke Aoyama ). + + When the $SHELL variable points to a Unix-style shell, Make + works just like you'd expect on Unix, calling the shell for any + command that involves characters special to the shell or + internal shell commands. The only difference is that, since + there is no standard way to pass command lines longer than the + infamous DOS 126-character limit, this port of Make writes the + command line to a temporary disk file and then invokes the shell + on that file. + + If $SHELL points to a DOS-style shell, however, Make will not + call it automatically, as it does with Unix shells. Stock + COMMAND.COM is too dumb and would unnecessarily limit the + functionality of Make. For example, you would not be able to + use long command lines in commands that use redirection or + pipes. Therefore, when presented with a DOS shell, this port of + Make will emulate most of the shell functionality, like + redirection and pipes, and shall only call the shell when a + batch file or a command internal to the shell is invoked. (Even + when a command is an internal shell command, Make will first + search the $PATH for it, so that if a Makefile calls 'mkdir', + you can install, say, a port of GNU 'mkdir' and have it called + in that case.) + + The key to all this is the extended functionality of 'spawn' and + 'system' functions from the DJGPP library; this port just calls + 'system' where it would invoke the shell on Unix. The most + important aspect of these functions is that they use a special + mechanism to pass long (up to 16KB) command lines to DJGPP + programs. In addition, 'system' emulates some internal + commands, like 'cd' (so that you can now use forward slashes + with it, and can also change the drive if the directory is on + another drive). Another aspect worth mentioning is that you can + call Unix shell scripts directly, provided that the shell whose + name is mentioned on the first line of the script is installed + anywhere along the $PATH. It is impossible to tell here + everything about these functions; refer to the DJGPP library + reference for more details. + + The $(shell) built-in is implemented in this port by calling + 'popen'. Since 'popen' calls 'system', the above considerations + are valid for $(shell) as well. In particular, you can put + arbitrary complex commands, including pipes and redirection, + inside $(shell), which is in many cases a valid substitute for + the Unix-style command substitution (`command`) feature. + + + 2. "SHELL=/bin/sh" -- or is it? + + Many Unix Makefiles include a line which sets the SHELL, for + those versions of Make which don't have this as the default. + Since many DOS systems don't have 'sh' installed (in fact, most + of them don't even have a '/bin' directory), this port takes + such directives with a grain of salt. It will only honor such a + directive if the basename of the shell name (like 'sh' in the + above example) can indeed be found in the directory that is + mentioned in the SHELL= line ('/bin' in the above example), or + in the current working directory, or anywhere on the $PATH (in + that order). If the basename doesn't include a filename + extension, Make will look for any known extension that indicates + an executable file (.exe, .com, .bat, .btm, .sh, and even .sed + and .pl). If any such file is found, then $SHELL will be + defined to the exact pathname of that file, and that shell will + hence be used for the rest of processing. But if the named + shell is *not* found, the line which sets it will be effectively + ignored, leaving the value of $SHELL as it was before. Since a + lot of decisions that this port makes depend on the gender of + the shell, I feel it doesn't make any sense to tailor Make's + behavior to a shell which is nowhere to be found. + + Note that the above special handling of "SHELL=" only happens + for Makefiles; if you set $SHELL in the environment or on the + Make command line, you are expected to give the complete + pathname of the shell, including the filename extension. + + The default value of $SHELL is computed as on Unix (see the Make + manual for details), except that if $SHELL is not defined in the + environment, $COMSPEC is used. Also, if an environment variable + named $MAKESHELL is defined, it takes precedence over both + $COMSPEC and $SHELL. Note that, unlike Unix, $SHELL in the + environment *is* used to set the shell (since on MSDOS, it's + unlikely that the interactive shell will not be suitable for + Makefile processing). + + The bottom line is that you can now write Makefiles where some + of the targets require a real (i.e. Unix-like) shell, which will + nevertheless work when such shell is not available (provided, of + course, that the commands which should always work, don't + require such a shell). More important, you can convert Unix + Makefiles to MSDOS and leave the line which sets the shell + intact, so that people who do have Unixy shell could use it for + targets which aren't converted to DOS (like 'install' and + 'uninstall', for example). + + + 3. Default directories. + + GNU Make knows about standard directories where it searches for + library and include files mentioned in the Makefile. Since + MSDOS machines don't have standard places for these, this port + will search ${DJDIR}/lib and ${DJDIR}/include respectively. + $DJDIR is defined automatically by the DJGPP startup code as the + root of the DJGPP installation tree (unless you've tampered with + the DJGPP.ENV file). This should provide reasonable default + values, unless you moved parts of DJGPP to other directories. + + + 4. Letter-case in filenames. + + If you run Make on Windows 9x, you should be aware of the + letter-case issue. Make is internally case-sensitive, but all + file operations are case-insensitive on Windows 9x, so + e.g. files 'FAQ', 'faq' and 'Faq' all refer to the same file, as + far as Windows is concerned. The underlying DJGPP C library + functions honor the letter-case of the filenames they get from + the OS, except that by default, they down-case 8+3 DOS filenames + which are stored in upper case in the directory and would break + many Makefiles otherwise. (The details of which filenames are + converted to lower case are explained in the DJGPP libc docs, + under the '_preserve_fncase' and '_lfn_gen_short_fname' + functions, but as a thumb rule, any filename that is stored in + upper case in the directory, is a valid DOS 8+3 filename and + doesn't include characters invalid on MSDOS FAT filesystems, + will be automatically down-cased.) User reports that I have + indicate that this default behavior is generally what you'd + expect; however, your input is most welcome. + + In any case, if you hit a situation where you must force Make to + get the 8+3 DOS filenames in upper case, set FNCASE=y in the + environment or in the Makefile. + + + 5. DOS-style pathnames. + + There are a lot of places throughout the program sources which + make implicit assumptions about the pathname syntax. In + particular, the directories are assumed to be separated by '/', + and any pathname which doesn't begin with a '/' is assumed to be + relative to the current directory. This port attempts to + support DOS-style pathnames which might include the drive letter + and use backslashes instead of forward slashes. However, this + support is not complete; I feel that pursuing this support too + far might break some more important features, particularly if + you use a Unix-style shell (where a backslash is a quote + character). I only consider support of backslashes desirable + because some Makefiles invoke non-DJGPP programs which don't + understand forward slashes. A notable example of such programs + is the standard programs which come with MSDOS. Otherwise, you + are advised to stay away from backslashes whenever possible. In + particular, filename globbing won't work on pathnames with + backslashes, because the GNU 'glob' library doesn't support them + (backslash is special in filename wildcards, and I didn't want + to break that). + + One feature which *does* work with backslashes is the filename- + related built-in functions such as $(dir), $(notdir), etc. + Drive letters in pathnames are also fully supported. + + + +Bug reports: +----------- + + Bugs that are clearly related to the MSDOS/DJGPP port should be + reported first on the comp.os.msdos.djgpp news group (if you cannot + post to Usenet groups, write to the DJGPP mailing list, + , which is an email gateway into the above news + group). For other bugs, please follow the procedure explained in + the "Bugs" chapter of the Info docs. If you don't have an Info + reader, look up that chapter in the 'make.i1' file with any text + browser/editor. + + + Enjoy, + Eli Zaretskii + + +------------------------------------------------------------------------------- +Copyright (C) 1996-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . diff --git a/src/kmk/README.OS2.template b/src/kmk/README.OS2.template new file mode 100644 index 0000000..0ce81b4 --- /dev/null +++ b/src/kmk/README.OS2.template @@ -0,0 +1,176 @@ +Port of GNU make to OS/2. + +Features of GNU make that do not work under OS/2: + - remote job execution + - dynamic load balancing + + +Special features of the OS/2 version: + +Due to the fact that some people might want to use sh syntax in +Makefiles while others might want to use OS/2's native shell cmd.exe, +GNU make supports both shell types. The following list defines the order +that is used to determine the shell: + + 1. The shell specified by the environment variable MAKESHELL. + 2. The shell specified by the SHELL variable within a Makefile. Like + Unix, SHELL is NOT taken from the environment. + 3. The shell specified by the COMSPEC environment variable. + 4. The shell specified by the OS2_SHELL environment variable. + 5. If none of the above is defined /bin/sh is used as default. This + happens e.g. in the make testsuite. + +Note: - Points 3 and 4 can be turned off at compile time by adding + -DNO_CMD_DEFAULT to the CPPFLAGS. + - DOS support is not tested for EMX and therefore might not work. + - The UNIXROOT environment variable is supported to find /bin/sh + if it is not on the current drive. + + +COMPILATION OF GNU MAKE FOR OS/2: + +I. ***** SPECIAL OPTIONS ***** + + - At compile time you can turn off that cmd is used as default shell + (but only /bin/sh). Simply set CPPFLAGS="-DNO_CMD_DEFAULT" and make + will not use cmd unless you cause it to do so by setting MAKESHELL to + cmd or by specifying SHELL=cmd in your Makefile. + + - At compile time you can set CPPFLAGS="-DNO_CHDIR2" to turn off that + GNU make prints drive letters. This is necessary if you want to run + the testsuite. + + +II. ***** REQUIREMENTS FOR THE COMPILATION ***** + +A standard Unix like build environment: + + - sh compatible shell (ksh, bash, ash, but tested only with pdksh 5.2.14 + release 2) + If you use pdksh it is recommended to update to 5.2.14 release 2. Older + versions may not work! You can get this version at + http://www.math.ohio-state.edu/~ilya/software/os2/pdksh-5.2.14-bin-2.zip + - GNU file utilities (make sure that install.exe from the file utilities + is in front of your PATH before X:\OS2\INSTALL\INSTALL.EXE. I recommend + also to change the filename to ginstall.exe instead of install.exe + to avoid confusion with X:\OS2\INSTALL\INSTALL.EXE) + - GNU shell utilities + - GNU text utilities + - gawk + - grep + - sed + - GNU make 3.79.1 (special OS/2 patched version) or higher + - perl 5.005 or higher + - GNU texinfo (you can use 3.1 (gnuinfo.zip), but I recommend 4.0) + +If you want to recreate the configuration files (developers only!) +you need also: GNU m4 1.4, autoconf 2.59, automake 1.9.6 (or compatible) + + +III. ***** COMPILATION AND INSTALLATION ***** + + a) ** Developers only - Everyone else should skip this section ** + To recreate the configuration files use: + + export EMXSHELL=ksh + aclocal -I config + automake + autoconf + autoheader + + +b) Installation into x:/usr + + Note: Although it is possible to compile make using "./configure", + "make", "make install" this is not recommended. In particular, + you must ALWAYS use LDFLAGS="-Zstack 0x6000" because the default + stack size is far to small and make will not work properly! + +Recommended environment variables and installation options: + + export ac_executable_extensions=".exe" + export CPPFLAGS="-D__ST_MT_ERRNO__" + export CFLAGS="-O2 -Zomf -Zmt" + export LDFLAGS="-Zcrtdll -Zlinker /exepack:2 -Zlinker /pm:vio -Zstack 0x6000" + export RANLIB="echo" + ./configure --prefix=x:/usr --infodir=x:/usr/share/info --mandir=x:/usr/share/man --without-included-gettext + make AR=emxomfar + make install + +Note: If you use gcc 2.9.x I recommend to set also LIBS="-lgcc" + +Note: You can add -DNO_CMD_DEFAULT and -DNO_CHDIR2 to CPPFLAGS. + See section I. for details. + + +IV. ***** NLS support ***** + +GNU make has NLS (National Language Support), with the following +caveats: + + a) It will only work with GNU gettext, and + b) GNU gettext support is not included in the GNU make package. + +Therefore, if you wish to enable the internationalization features of +GNU make you must install GNU gettext on your system before configuring +GNU make. + +You can choose the languages to be installed. To install support for +English, German and French only enter: + + export LINGUAS="en de fr" + +If you don't specify LINGUAS all languages are installed. + +If you don't want NLS support (English only) use the option +--disable-nls for the configure script. Note if GNU gettext is not +installed then NLS will not be enabled regardless of this flag. + + +V. ***** Running the make test suite ***** + +To run the included make test suite you have to set + + CPPFLAGS="-D__ST_MT_ERRNO__ -DNO_CMD_DEFAULT -DNO_CHDIR2" + +before you compile make. This is due to some restrictions of the +testsuite itself. -DNO_CMD_DEFAULT causes make to use /bin/sh as default +shell in every case. Normally you could simply set MAKESHELL="/bin/sh" +to do this but the testsuite ignores the environment. -DNO_CHDIR2 causes +make not to use drive letters for directory names (i.e. _chdir2() and +_getcwd2() are NOT used). The testsuite interpretes the whole output of +make, especially statements like make[1]: Entering directory +'C:/somewhere/make-3.79.1/tests' where the testsuite does not expect the +drive letter. This would be interpreted as an error even if there is +none. + +To run the testsuite do the following: + + export CPPFLAGS="-D__ST_MT_ERRNO__ -DNO_CMD_DEFAULT -DNO_CHDIR2" + export CFLAGS="-Zomf -O2 -Zmt" + export LDFLAGS="-Zcrtdll -s -Zlinker /exepack:2 -Zlinker /pm:vio -Zstack 0x6000" + export RANLIB="echo" + ./configure --prefix=x:/usr --disable-nls + make AR=emxomfar + make check + +All tests should work fine with the exception of one of the "INCLUDE_DIRS" +tests which will fail if your /usr/include directory is on a drive different +from the make source tree. + + +------------------------------------------------------------------------------- +Copyright (C) 2003-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . diff --git a/src/kmk/README.VMS b/src/kmk/README.VMS new file mode 100644 index 0000000..5532b01 --- /dev/null +++ b/src/kmk/README.VMS @@ -0,0 +1,515 @@ +Overview: -*-text-mode-*- +--------- + + This version of GNU make has been tested on: + OpenVMS V8.3/V8.4 (Alpha) and V8.4 (Integrity) AND V7.3 (VAX) + + This version of GNU Make is intended to be run from DCL to run + make scripts with a special syntax that is described below. It + likely will not be able to run unmodified Unix makefiles. + + There is an older implementation of GNU Make that was ported to GNV. + Work is now in progress to merge that port to get a single version + of GNU Make available. When that merge is done, GNU Make will auto + detect that it is running under a Posix shell and then operate as close to + GNU Make on Unix as possible. + + The descriptions below are for running GNU make from DCL or equivalent. + +Recipe differences: +------------------- + + GNU Make for OpenVMS can not currently run native Unix make files because of + differences in the implementation. + + I am trying to document the current behavior in this section. This is based + on the information in the file NEWS. and running the test suite. + TODO: More tests are needed to validate and demonstrate the OpenVMS + expected behavior. + + In some cases the older behavior of GNU Make when run from DCL is not + compatible with standard makefile behavior. + + This behavior can be changed when running GNU Make from DCL by setting + either DCL symbols or logical names of the format GNV$. The settings + are enabled with a string starting with one of '1', 'T', or 'E' for "1", + "TRUE", or "ENABLE". They are disabled with a '0', 'F', or 'D' for "1", + "FALSE", or "DISABLE". If they are not explicitly set to one of these + values, then they will be set to their default values. + + The value of the setting DECC$FILENAME_UNIX_REPORT or + DECC$FILENAME_UNIX_ONLY will now cause the $(dir x) function to return + './' or '[]' as appropriate. + + The name GNV$MAKE_OLD_VMS when enabled will cause GNU Make to behave as + much as the older method as can be done with out disabling VMS features. + When it is disabled GNU Make have the new behavior which more closely + matches Unix Make behavior. + + The default is currently the old behavior when running GNU Make from DCL. + In the future this may change. When running make from GNV Bash the new + behavior is the default. + + This is a global setting that sets the default behavior for several other + options that can be individually changed. Many of the individual settings + are to make it so that the self tests for GNU Make need less VMS specific + modifications. + + The name GNV$MAKE_COMMA when enabled will cause GNU Make to expect a comma + for a path separator and use a comma for the separator for a list of files. + When disabled, it will cause GNU Make to use a colon for a path separator + and a space for the separator for a list of files. The default is to be + enabled if the GNU Make is set to the older behavior. + + The name GNV$MAKE_SHELL_SIM when enabled will cause GNU Make to try to + simulate a Posix shell more closely. The following behaviors occur: + + * Single quotes are converted to double quotes and any double + quotes inside of them are doubled. No environment variable expansion + is simulated. + * A exit command status will be converted to a Posix Exit + where 0 is success and non-zero is failure. + * The $ character will cause environment variable expansion. + * Environent variables can be set on the command line before a command. + + VMS generally uses logical name search lists instead of path variables + where the resolution is handled by VMS independent of the program. Which + means that it is likely that nothing will notice if the default path + specifier is changed in the future. + + Currently the built in VMS specific macros and recipes depend on the comma + being used as a file list separator. + TODO: Remove this dependency as other functions in GNU Make depend on a + space being used as a separator. + + The format for recipes are a combination of Unix macros, a subset of + simulated UNIX commands, some shell emulation, and OpenVMS commands. + This makes the resulting makefiles unique to the OpenVMS port of GNU make. + + If you are creating a OpenVMS specific makefile from scratch, you should also + look at MMK (Madgoat Make) available at https://github.com/endlesssoftware/mmk + MMK uses full OpenVMS syntax and a persistent subprocess is used for the + recipe lines, allowing multiple line rules. + + The default makefile search order is "makefile.vms", "gnumakefile", + "makefile". TODO: See if that lookup is case sensitive. + + When Make is invoked from DCL, it will create a foreign command + using the name of executable image, with any facility prefix removed, + for the duration of the make program, so it can be used internally + to recursively run make(). The macro MAKE_COMMAND will be set to + this foreign command. + + When make is launched from an exec*() command from a C program, + the foreign command is not created. The macro MAKE_COMMAND will be + set to the actual command passed as argv[0] to the exec*() function. + + If the DCL symbol or logical name GNV$MAKE_USE_MCR exists, then + the macro MAKE_COMMAND will be set to be an "MCR" command with the + absolute path used by DCL to launch make. The foreign command + will not be created. + + The macro MAKE is set to be the same value as the macro MAKE_COMMAND + on all platforms. + + Each recipe command is normally run as a separate spawned processes, + except for the cases documented below where a temporary DCL command + file may be used. + + BUG: Testing has shown that the commands in the temporary command files + are not always created properly. This issue is still under investigation. + + Any macros marked as exported are temporarily created as DCL symbols + for child images to use. DCL symbol substitution is not done with these + commands. + Untested: Symbol substitution. + + When a temporary DCL command file is used, DCL symbol substitution + will work. + + For VMS 7.3-1 and earlier, command lines are limited to 255 characters + or 1024 characters in a command file. + For VMS 7.3-2 and later, command lines are limited to 4059 characters + or 8192 characters in a command file. + + VMS limits each token of a command line to 256 characters, and limits + a command line to 127 tokens. + + Command lines above the limit length are written to a command file + in sys$scratch:. + + In order to handle Unix style extensions to VMS DCL, GNU Make has + parsed the recipe commands and them modified them as needed. The + parser has been re-written to resolve numerous bugs in handling + valid VMS syntax and potential buffer overruns. + + The new parser may need whitespace characters where DCL does not require + it, and also may require that quotes are matched were DCL forgives if + they are not. There is a small chance that existing VMS specific makefiles + will be affected. + + The '<', '>' was previously implemented using command files. Now + GNU Make will check to see if the is already a VMS "PIPE" command and + if it is not, will convert the command to a VMS "PIPE" command. + + The '>>' redirection has been implemented by using a temporary command file. + This will be described later. + + The DCL symbol or logical name GNV$MAKE_USE_CMD_FILE when set to a + string starting with one of '1','T', or 'E' for "1", "TRUE", or "ENABLE", + then temporary DCL command files are always used for running commands. + + Some recipe strings with embedded new lines will not be handled correctly + when a command file is used. + + GNU Make generally does text comparisons for the targets and sources. The + make program itself can handle either Unix or OpenVMS format filenames, but + normally does not do any conversions from one format to another. + TODO: The OpenVMS format syntax handling is incomplete. + TODO: ODS-5 EFS support is missing. + BUG: The internal routines to convert filenames to and from OpenVMS format + do not work correctly. + + Note: In the examples below, line continuations such as a backslash may have + been added to make the examples easier to read in this format. + BUG: That feature does not completely work at this time. + + Since the OpenVMS utilities generally expect OpenVMS format paths, you will + usually have to use OpenVMS format paths for rules and targets. + BUG: Relative OpenVMS paths may not work in targets, especially combined + with vpaths. This is because GNU make will just concatenate the directories + as it does on Unix. + + The variables $^ and $@ separate files with commas instead of spaces. + This is controlled by the name GNV$MAKE_COMMA as documented in the + previous section. + + While this may seem the natural thing to do with OpenVMS, it actually + causes problems when trying to use other make functions that expect the + files to be separated by spaces. If you run into this, you need the + following workaround to convert the output. + TODO: Look at have the $^ and $@ use spaces like on Unix and have + and easy to use function to do the conversions and have the built + in OpenVMS specific recipes and macros use it. + + Example: + +comma := , +empty := +space := $(empty) $(empty) + +foo: $(addsuffix .3,$(subs $(comma),$(space),$^) + + + Makefile variables are looked up in the current environment. You can set + symbols or logicals in DCL and evaluate them in the Makefile via + $(). Variables defined in the Makefile + override OpenVMS symbols/logicals. + + OpenVMS logical and symbols names show up as "environment" using the + origin function. when the "-e" option is specified, the origion function + shows them as "environment override". On Posix the test scripts indicate + that they should show up just as "environment". + + When GNU make reads in a symbol or logical name into the environment, it + converts any dollar signs found to double dollar signs for convenience in + using DCL symbols and logical names in recipes. When GNU make exports a + DCL symbol for a child process, if the first dollar sign found is followed + by second dollar sign, then all double dollar signs will be convirted to + single dollar signs. + + The variable $(ARCH) is predefined as IA64, ALPHA or VAX respectively. + Makefiles for different OpenVMS systems can now be written by checking + $(ARCH). Since IA64 and ALPHA are similar, usually just a check for + VAX or not VAX is sufficient. + + You may have to update makefiles that assume VAX if not ALPHA. + +ifeq ($(ARCH),VAX) + $(ECHO) "On the VAX" +else + $(ECHO) "On the ALPHA or IA64" +endif + + Empty commands are handled correctly and don't end in a new DCL process. + + The exit command needs to have OpenVMS exit codes. To pass a Posix code + back to the make script, you need to encode it by multiplying it by 8 + and then adding %x1035a002 for a failure code and %x1035a001 for a + success. Make will interpret any posix code other than 0 as a failure. + TODO: Add an option have simulate Posix exit commands in recipes. + + Lexical functions can be used in pipes to simulate shell file test rules. + + Example: + + Posix: +b : c ; [ -f $@ ] || echo >> $@ + + OpenVMS: +b : c ; if f$$search("$@") then pipe open/append xx $@ ; write xx "" ; close xx + + + You can also use pipes and turning messages off to silently test for a + failure. + +x = %x1035a00a + +%.b : %.c +pipe set mess/nofac/noiden/nosev/notext ; type $^/output=$@ || exit $(x) + + +Runtime issues: + + The OpenVMS C Runtime has a convention for encoding a Posix exit status into + to OpenVMS exit codes. These status codes will have the hex value of + 0x35a000. OpenVMS exit code may also have a hex value of %x10000000 set on + them. This is a flag to tell DCL not to write out the exit code. + + To convert an OpenVMS encoded Posix exit status code to the original code + You subtract %x35a000 and any flags from the OpenVMS code and divide it by 8. + + WARNING: Backward-incompatibility! + The make program exit now returns the same encoded Posix exit code as on + Unix. Previous versions returned the OpenVMS exit status code if that is what + caused the recipe to fail. + TODO: Provide a way for scripts calling make to obtain that OpenVMS status + code. + + Make internally has two error codes, MAKE_FAILURE and MAKE_TROUBLE. These + will have the error "-E-" severity set on exit. + + MAKE_TROUBLE is returned only if the option "-q" or "--question" is used and + has a Posix value of 1 and an OpenVMS status of %x1035a00a. + + MAKE_FAILURE has a Posix value of 2 and an OpenVMS status of %x1035a012. + + Output from GNU make may have single quotes around some values where on + other platforms it does not. Also output that would be in double quotes + on some platforms may show up as single quotes on VMS. + + There may be extra blank lines in the output on VMS. + https://savannah.gnu.org/bugs/?func=detailitem&item_id=41760 + + There may be a "Waiting for unfinished jobs..." show up in the output. + + Error messages generated by Make or Unix utilities may slightly vary from + Posix platforms. Typically the case may be different. + + When make deletes files, on posix platforms it writes out 'rm' and the list + of files. On VMS, only the files are writen out, one per line. + TODO: VMS + + There may be extra leading white space or additional or missing whitespace + in the output of recipes. + + GNU Make uses sys$scratch: for the tempfiles that it creates. + + The OpenVMS CRTL library maps /tmp to sys$scratch if the TMP: logical name + does not exist. As the CRTL may use both sys$scratch: and /tmp internally, + if you define the TMP logical name to be different than SYS$SCRATCH:, + you may end up with only some temporary files in TMP: and some in SYS$SCRATCH: + + The default include directory for including other makefiles is + SYS$SYSROOT:[SYSLIB] (I don't remember why I didn't just use + SYS$LIBRARY: instead; maybe it wouldn't work that way). + TODO: A better default may be desired. + + If the device for a file in a recipe does not exist, on OpenVMS an error + message of "stat: : no such device or address" will be output. + + Make ignores success, informational, or warning errors (-S-, -I-, or + -W-). But it will stop on -E- and -F- errors. (unless you do something + to override this in your makefile, or whatever). + + +Unix compatibilty features: +--------------------------- + + If the command 'echo' is seen, any single quotes on the line will be + converted to double quotes. + + The variable $(CD) is implemented as a built in Change Directory + command. This invokes the 'builtin_cd' Executing a 'set default' + recipe doesn't do the trick, since it only affects the subprocess + spawned for that command. + + The 'builtin_cd' is generally expected to be on its own line. + The 'builtin_cd' either from the expansion of $(CD) or directly + put in a recipe line will be executed before any other commands in + that recipe line. DCL parameter substitution will not work for the + 'builtin_cd' command. + + Putting a 'builtin_cd' in a pipeline or an IF-THEN line should not be + done because the 'builtin_cd' is always executed + and executed first. The directory change is persistent. + + Unix shell style I/O redirection is supported. You can now write lines like: + "mcr sys$disk:[]program.exe < input.txt > output.txt &> error.txt" + + Posix shells have ":" as a null command. These are now handled. + https://savannah.gnu.org/bugs/index.php?41761 + + A note on appending the redirected output. A simple mechanism is + implemented to make ">>" work in action lines. In OpenVMS there is no simple + feature like ">>" to have DCL command or program output redirected and + appended to a file. GNU make for OpenVMS implements the redirection + of ">>" by using a command procedure. + + The current algorithm creates the output file if it does not exist and + then uses the DCL open/append to extend it. SYS$OUTPUT is then directed + to that file. + + The implementation supports only one redirected append output to a file + and that redirection is done before any other commands in that line + are executed, so it redirects all output for that command. + + The older implementation wrote the output to a temporary file in + in sys$scratch: and then attempted to append the file to the existing file. + The temporary file names looked like "CMDxxxxx.". Any time the created + command procedure can not complete, this happens. Pressing Ctrl+Y to + abort make is one case. + + In case of Ctrl+Y the associated command procedure is left in SYS$SCRATCH:. + The command procedures will be named gnv$make_cmd*.com. + + The CtrlY handler now uses $delprc to delete all children. This way also + actions with DCL commands will be stopped. As before the CtrlY handler + then sends SIGQUIT to itself, which is handled in common code. + + Temporary command files are now deleted in the OpenVMS child termination + handler. That deletes them even if a Ctrl+C was pressed. + TODO: Does the previous section about >> leaving files still apply? + + The behavior of pressing Ctrl+C is not changed. It still has only an effect, + after the current action is terminated. If that doesn't happen or takes too + long, Ctrl+Y should be used instead. + + +Build Options: + + Added support to have case sensitive targets and dependencies but to + still use case blind file names. This is especially useful for Java + makefiles on VMS: + +.SUFFIXES : +.SUFFIXES : .class .java +.java.class : +javac "$<" +HelloWorld.class : HelloWorld.java + + A new macro WANT_CASE_SENSITIVE_TARGETS in config.h-vms was introduced. + It needs to be enabled to get this feature; default is disabled. + TODO: This should be a run-time setting based on if the process + has been set to case sensitive. + + +Unimplemented functionality: + + The new feature "Loadable objects" is not yet supported. If you need it, + please send a change request or submit a bug report. + + The new option --output-sync (-O) is accepted but has no effect: GNU make + for OpenVMS does not support running multiple commands simultaneously. + + +Self test failures and todos: +----------------------------- + + The test harness can not handle testing some of the VMS specific modes + because of the features needed for to be set for the Perl to run. + Need to find a way to set the VMS features before running make as a + child. + + GNU make was not currently translating the OpenVMS encoded POSIX values + returned to it back to the Posix values. I have temporarily modified the + Perl test script to compensate for it. This should be being handled + internally to Make. + TODO: Verify and update the Perl test script. + + The features/parallelism test was failing. OpenVMS is executing the rules + in sequence not in parallel as this feature was not implemented. + GNU Make on VMS no longer claims it is implemented. + TODO: Implement it. + + Symlink support is not present. Symlinks are supported by OpenVMS 8.3 and + later. + + Error messages should be supressed with the "-" at the beginning of a line. + On openVMS they were showing up. TODO: Is this still an issue? + + The internal vmsify and unixify OpenVMS to/from UNIX are not handling logical + names correctly. + + +Build instructions: +------------------ + + Don't use the HP C V7.2-001 compiler, which has an incompatible change + how __STDC__ is defined. This results at least in compile time warnings. + +Make a 1st version + $ @makefile.com ! ignore any compiler and/or linker warning + $ copy make.exe 1st-make.exe + + Use the 1st version to generate a 2nd version as a test. + $ mc sys$disk:[]1st-make clean ! ignore any file not found messages + $ mc sys$disk:[]1st-make + + Verify your 2nd version by building Make again. + $ copy make.exe 2nd-make.exe + $ mc sys$disk:[]2nd-make clean + $ mc sys$disk:[]2nd-make + + +Running the tests: +------------------ + + Running the tests on OpenVMS requires the following software to be installed + as most of the tests are Unix oriented. + + * Perl 5.18 or later. + https://sourceforge.net/projects/vmsperlkit/files/ + * GNV 2.1.3 + Updates including a minimum of: + * Bash 4.3.30 + * ld_tools 3.0.2 + * coreutils 8.21 + https://sourceforge.net/p/gnv/wiki/InstallingGNVPackages/ + https://sourceforge.net/projects/gnv/files/ + + As the test scripts need to create some foreign commands that persist + after the test is run, it is recommend that either you use a subprocess or + a dedicated login to run the tests. + + To get detailed information for running the tests: + + $ set default [.tests] + $ @run_make_tests help + + Running the script with no parameters will run all the tests. + + After the the test script has been run once in a session, assuming + that you built make in sys$disk:[make], you can redefined the + "bin" logical name as follows: + + $ define bin sys$disk:[make],gnv$gnu:[bin] + + Then you can use Perl to run the scripts. + + $ perl run_make_tests.pl + + +Acknowlegements: +---------------- + +See NEWS. for details of past changes. + + These are the currently known contributers to this port. + + Hartmut Becker + John Malmberg + Michael Gehre + John Eisenbraun + Klaus Kaempf + Mike Moretti + John W. Eaton diff --git a/src/kmk/README.W32.template b/src/kmk/README.W32.template new file mode 100644 index 0000000..3ac3354 --- /dev/null +++ b/src/kmk/README.W32.template @@ -0,0 +1,314 @@ +This version of GNU make has been tested on: + Microsoft Windows 2000/XP/2003/Vista/7/8/10 +It has also been used on Windows 95/98/NT, and on OS/2. + +It builds with the MinGW port of GCC (tested with GCC 3.4.2, 4.8.1, +and 4.9.3). + +It also builds with MSVC 2.x, 4.x, 5.x, 6.x, 2003, and 14 (2015) as +well as with .NET 7.x and .NET 2003. + +As of version 4.0, a build with Guile is supported (tested with Guile +2.0.3). To build with Guile, you will need, in addition to Guile +itself, its dependency libraries and the pkg-config program. The +latter is used to figure out which compilation and link switches and +libraries need to be mentioned on the compiler command lines to +correctly link with Guile. A Windows port of pkg-config can be found +on ezwinports site: + + http://sourceforge.net/projects/ezwinports/ + +The libraries on which Guile depends can vary depending on your +version and build of Guile. At the very least, the Boehm's GC library +will be needed, and typically also GNU MP, libffi, libunistring, and +libtool's libltdl. Whoever built the port of Guile you have should +also provide you with these dependencies or a URL where to download +them. A precompiled 32-bit Windows build of Guile is available from +the ezwinports site mentioned above. + +The Windows port of GNU make is maintained jointly by various people. +It was originally made by Rob Tulloh. +It is currently maintained by Eli Zaretskii. + + +Do this first, regardless of the build method you choose: +--------------------------------------------------------- + + 1. Edit config.h.W32 to your liking (especially the few shell-related + defines near the end, or HAVE_CASE_INSENSITIVE_FS which corresponds + to './configure --enable-case-insensitive-file-system'). (We don't + recommend to define HAVE_CASE_INSENSITIVE_FS, but you may wish to + consider that if you have a lot of files whose names are in upper + case, while Makefile rules are written for lower-case versions.) + + +Using make_msvc_net2003.vcproj +------------------------------ + + 2. Open make_msvc_net2003.vcproj in MSVS71 or MSVC71 or any compatible IDE, + then build this project as usual. There's also a solution file for + Studio 2003. + + +Building with (MinGW-)GCC using build_w32.bat +--------------------------------------------- + + 2. Open a W32 command prompt for your installed (MinGW-)GCC, setup a + correct PATH and other environment variables for it, then execute ... + + build_w32.bat gcc + + This produces gnumake.exe in the GccRel directory. + If you want a version of GNU make built with debugging enabled, + add the --debug option. + + The batch file will probe for Guile installation, and will build + gnumake.exe with Guile if it finds it. If you have Guile + installed, but want to build Make without Guile support, type + + build_w32.bat --without-guile gcc + + +Building with (MSVC++-)cl using build_w32.bat or NMakefile +---------------------------------------------------------- + + 2. Open a W32 command prompt for your installed (MSVC++-)cl, setup a + correct PATH and other environment variables for it (usually via + executing vcvars32.bat or vsvars32.bat from the cl-installation, + e.g. "%VS71COMNTOOLS%vsvars32.bat"; or using a corresponding start + menue entry from the cl-installation), then execute EITHER ... + + build_w32.bat + + This produces gnumake.exe in the WinRel directory. + If you want a version of GNU make built with debugging enabled, + add the --debug option. + + ... OR ... + + nmake /f NMakefile + + (this produces WinDebug/make.exe and WinRel/make.exe). + + The batch file will probe for Guile installation, and will build + gnumake.exe with Guile if it finds it. If you have Guile + installed, but want to build Make without Guile support, type + + build_w32.bat --without-guile + +------------------- +-- Notes/Caveats -- +------------------- + +GNU make on Windows 32-bit platforms: + + This version of make is ported natively to Windows32 platforms + (Windows NT 3.51, Windows NT 4.0, Windows 2000, Windows XP, + Windows 95, and Windows 98). It does not rely on any 3rd party + software or add-on packages for building. The only thing + needed is a Windows compiler. Two compilers supported + officially are the MinGW port of GNU GCC, and the various + versions of the Microsoft C compiler. + + Do not confuse this port of GNU make with other Windows32 projects + which provide a GNU make binary. These are separate projects + and are not connected to this port effort. + +GNU make and sh.exe: + + This port prefers if you have a working sh.exe somewhere on + your system. If you don't have sh.exe, the port falls back to + MSDOS mode for launching programs (via a batch file). The + MSDOS mode style execution has not been tested that carefully + though (The author uses GNU bash as sh.exe). + + There are very few true ports of Bourne shell for NT right now. + There is a version of GNU bash available from Cygnus "Cygwin" + porting effort (http://www.cygwin.com/). + Other possibilities are the MKS version of sh.exe, or building + your own with a package like NutCracker (DataFocus) or Portage + (Consensys). Also MinGW includes sh (http://mingw.org/). + +GNU make and brain-dead shells (BATCH_MODE_ONLY_SHELL): + + Some versions of Bourne shell do not behave well when invoked + as 'sh -c' from CreateProcess(). The main problem is they seem + to have a hard time handling quoted strings correctly. This can + be circumvented by writing commands to be executed to a batch + file and then executing the command by calling 'sh file'. + + To work around this difficulty, this version of make supports + a batch mode. When BATCH_MODE_ONLY_SHELL is defined at compile + time, make forces all command lines to be executed via script + files instead of by command line. In this mode you must have a + working sh.exe in order to use parallel builds (-j). + + A native Windows32 system with no Bourne shell will also run + in batch mode. All command lines will be put into batch files + and executed via $(COMSPEC) (%COMSPEC%). However, parallel + builds ARE supported with Windows shells (cmd.exe and + command.com). See the next section about some peculiarities + of parallel builds on Windows. + +Support for parallel builds + + Parallel builds (-jN) are supported in this port, with 1 + limitation: The number of concurrent processes has a hard + limit of 64, due to the way this port implements waiting for + its subprocesses. + +GNU make and Cygnus GNU Windows32 tools: + + Good news! Make now has native support for Cygwin sh. To enable, + define the HAVE_CYGWIN_SHELL in config.h and rebuild make + from scratch. This version of make tested with B20.1 of Cygwin. + Do not define BATCH_MODE_ONLY_SHELL if you use HAVE_CYGWIN_SHELL. + +GNU make and the MKS shell: + + There is now semi-official support for the MKS shell. To turn this + support on, define HAVE_MKS_SHELL in the config.h.W32 before you + build make. Do not define BATCH_MODE_ONLY_SHELL if you turn + on HAVE_MKS_SHELL. + +GNU make handling of drive letters in pathnames (PATH, vpath, VPATH): + + There is a caveat that should be noted with respect to handling + single character pathnames on Windows systems. When colon is + used in PATH variables, make tries to be smart about knowing when + you are using colon as a separator versus colon as a drive + letter. Unfortunately, something as simple as the string 'x:/' + could be interpreted 2 ways: (x and /) or (x:/). + + Make chooses to interpret a letter plus colon (e.g. x:/) as a + drive letter pathname. If it is necessary to use single + character directories in paths (VPATH, vpath, Path, PATH), the + user must do one of two things: + + a. Use semicolon as the separator to disambiguate colon. For + example use 'x;/' if you want to say 'x' and '/' are + separate components. + + b. Qualify the directory name so that there is more than + one character in the path(s) used. For example, none + of these settings are ambiguous: + + ./x:./y + /some/path/x:/some/path/y + x:/some/path/x:x:/some/path/y + + Please note that you are free to mix colon and semi-colon in the + specification of paths. Make is able to figure out the intended + result and convert the paths internally to the format needed + when interacting with the operating system, providing the path + is not within quotes, e.g. "x:/test/test.c". + + You are encouraged to use colon as the separator character. + This should ease the pain of deciding how to handle various path + problems which exist between platforms. If colon is used on + both Unix and Windows systems, then no ifdef'ing will be + necessary in the makefile source. + +GNU make test suite: + + I verified all functionality with a slightly modified version + of make-test-%VERSION% (modifications to get test suite to run + on Windows NT). All tests pass in an environment that includes + sh.exe. Tests were performed on both Windows NT and Windows 95. + +Pathnames and white space: + + Unlike Unix, Windows 95/NT systems encourage pathnames which + contain white space (e.g. C:\Program Files\). These sorts of + pathnames are valid on Unix too, but are never encouraged. + There is at least one place in make (VPATH/vpath handling) where + paths containing white space will simply not work. There may be + others too. I chose to not try and port make in such a way so + that these sorts of paths could be handled. I offer these + suggestions as workarounds: + + 1. Use 8.3 notation. i.e. "x:/long~1/", which is actually + "x:\longpathtest". Type "dir /x" to view these filenames + within the cmd.exe shell. + 2. Rename the directory so it does not contain white space. + + If you are unhappy with this choice, this is free software + and you are free to take a crack at making this work. The code + in w32/pathstuff.c and vpath.c would be the places to start. + +Pathnames and Case insensitivity: + + Unlike Unix, Windows 95/NT systems are case insensitive but case + preserving. For example if you tell the file system to create a + file named "Target", it will preserve the case. Subsequent access to + the file with other case permutations will succeed (i.e. opening a + file named "target" or "TARGET" will open the file "Target"). + + By default, GNU make retains its case sensitivity when comparing + target names and existing files or directories. It can be + configured, however, into a case preserving and case insensitive + mode by adding a define for HAVE_CASE_INSENSITIVE_FS to + config.h.W32. + + For example, the following makefile will create a file named + Target in the directory subdir which will subsequently be used + to satisfy the dependency of SUBDIR/DepTarget on SubDir/TARGET. + Without HAVE_CASE_INSENSITIVE_FS configured, the dependency link + will not be made: + + subdir/Target: + touch $@ + + SUBDIR/DepTarget: SubDir/TARGET + cp $^ $@ + + Reliance on this behavior also eliminates the ability of GNU make + to use case in comparison of matching rules. For example, it is + not possible to set up a C++ rule using %.C that is different + than a C rule using %.c. GNU make will consider these to be the + same rule and will issue a warning. + +SAMBA/NTFS/VFAT: + + I have not had any success building the debug version of this + package using SAMBA as my file server. The reason seems to be + related to the way VC++ 4.0 changes the case name of the pdb + filename it is passed on the command line. It seems to change + the name always to to lower case. I contend that the VC++ + compiler should not change the casename of files that are passed + as arguments on the command line. I don't think this was a + problem in MSVC 2.x, but I know it is a problem in MSVC 4.x. + + The package builds fine on VFAT and NTFS filesystems. + + Most all of the development I have done to date has been using + NTFS and long file names. I have not done any considerable work + under VFAT. VFAT users may wish to be aware that this port of + make does respect case sensitivity. + +FAT: + + Version 3.76 added support for FAT filesystems. Make works + around some difficulties with stat'ing of files and caching of + filenames and directories internally. + +Bug reports: + + Please submit bugs via the normal bug reporting mechanism which + is described in the GNU make manual and the base README. + +------------------------------------------------------------------------------- +Copyright (C) 1996-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . diff --git a/src/kmk/README.customs b/src/kmk/README.customs new file mode 100644 index 0000000..67e1252 --- /dev/null +++ b/src/kmk/README.customs @@ -0,0 +1,112 @@ + -*-indented-text-*- + +GNU make can utilize the Customs library, distributed with Pmake, to +provide builds distributed across multiple hosts. + +In order to utilize this capability, you must first download and build +the Customs library. It is contained in the Pmake distribution, which +can be obtained at: + + ftp://ftp.icsi.berkeley.edu/pub/ai/stolcke/software/ + +This integration was tested (superficially) with Pmake 2.1.33. + + +BUILDING CUSTOMS +---------------- + +First, build pmake and Customs. You need to build pmake first, because +Customs require pmake to build. Unfortunately, this is not trivial; +please see the pmake and Customs documentation for details. The best +place to look for instructions is in the pmake-2.1.33/INSTALL file. + +Note that the 2.1.33 Pmake distribution comes with a set of patches to +GNU make, distributed in the pmake-2.1.33/etc/gnumake/ directory. These +patches are based on GNU make 3.75 (there are patches for earlier +versions of GNU make, also). The parts of this patchfile which relate +directly to Customs support have already been incorporated into this +version of GNU make, so you should _NOT_ apply the patch file. + +However, there are a few non-Customs specific (as far as I could tell) +changes here which are not incorporated (for example, the modification +to try expanding -lfoo to libfoo.so). If you rely on these changes +you'll need to re-apply them by hand. + +Install the Customs library and header files according to the +documentation. You should also install the man pages (contrary to +comments in the documentation, they weren't installed automatically for +me; I had to cd to the 'pmake-2.1.33/doc' directory and run 'pmake +install' there directly). + + +BUILDING GNU MAKE +----------------- + +Once you've installed Customs, you can build GNU make to use it. When +configuring GNU make, merely use the '--with-customs=DIR' option. +Provide the directory containing the 'lib' and 'include/customs' +subdirectories as DIR. For example, if you installed the customs +library in /usr/local/lib and the headers in /usr/local/include/customs, +then you'd pass '--with-customs=/usr/local' as an option to configure. + +Run make (or use build.sh) normally to build GNU make as described in +the INSTALL file. + +See the documentation for Customs for information on starting and +configuring Customs. + + +INVOKING CUSTOMS-IZED GNU MAKE +----------------------------- + +One thing you should be aware of is that the default build environment +for Customs requires root permissions. Practically, this means that GNU +make must be installed setuid root to use Customs. + +If you don't want to do this, you can build Customs such that root +permissions are not necessary. Andreas Stolcke +writes: + + > pmake, gnumake or any other customs client program is not required to + > be suid root if customs was compiled WITHOUT the USE_RESERVED_PORTS + > option in customs/config.h. Make sure the "customs" service in + > /etc/services is defined accordingly (port 8231 instead of 1001). + + > Not using USE_RESERVED_PORTS means that a user with programming + > skills could impersonate another user by writing a fake customs + > client that pretends to be someone other than himself. See the + > discussion in etc/SECURITY. + + +PROBLEMS +-------- + +SunOS 4.1.x: + The customs/sprite.h header file #includes the header + files; this conflicts with GNU make's configuration so you'll get a + compile error if you use GCC (or any other ANSI-capable C compiler). + + I commented out the #include in sprite.h:107: + + #if defined(sun) || defined(ultrix) || defined(hpux) || defined(sgi) + /* #include */ + #else + + YMMV. + + +------------------------------------------------------------------------------- +Copyright (C) 1998-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . diff --git a/src/kmk/README.git b/src/kmk/README.git new file mode 100644 index 0000000..41a7675 --- /dev/null +++ b/src/kmk/README.git @@ -0,0 +1,292 @@ + -*-text-*- + +------------------------------------------------------------------------------- +Copyright (C) 2002-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +------------------------------------------------------------------------------- + +Obtaining Git Code +------------------ + +This seems redundant, since if you're reading this you most likely have +already performed this step; however, for completeness, you can obtain the GNU +make source code via Git from the FSF's Savannah project +: + + $ git clone git://git.savannah.gnu.org/make.git + + +Changes using Git +----------------- + +For non-developers, you can continue to provide patches as before, or if you +make a public repository I can pull from that if you prefer. + +Starting with GNU make 4.0 we no longer keep a separate ChangeLog file in +source control. We use the Gnulib git-to-changelog conversion script to +convert the Git comments into ChangeLog-style entries for release. As a +result, please format your Git comments carefully so they will look clean +after conversion. In particular, each line of your comment will have a TAB +added before it so be sure your comment lines are not longer than 72 +characters; prefer 70 or less. Please use standard ChangeLog formats for +your commit messages (sans the leading TAB of course). + +Rule #1: Don't rewrite pushed history (don't use "git push --force"). + +Typical simple workflow might be: + + * Edit files + * Use "git status" and "git diff" to verify your changes + * Use "git add" to stage the changes you want to make + * Use "git commit" to commit the staged changes to your local repository + * Use "git pull" to accept & merge new changes from the Savannah repository + * Use "git push" to push your commits back to the Savannah repository + +For Emacs users, there are many options for Git integration but I strongly +recommend the Magit package: http://www.emacswiki.org/emacs/Magit +It makes the workflow much clearer, and has advanced features such as +constructing multiple commits from various files and even from different +diff chunks in the same file. There is a video available which helps a lot. + + +Coding Standards +---------------- + +GNU make code adheres to the GNU Coding Standards. Please use only spaces and +no TAB characters in source code. + +Additionally, GNU make is a foundational bootstrap package for the GNU +project; as such it is very conservative about language features it expects. +It should build with any C compiler conforming to the ANSI C89 / ISO C90 +standard. + + +Building From Git +----------------- + +To build GNU make from Git, you will need Autoconf, Automake, and +Gettext, and any tools that those utilities require (GNU m4, Perl, +etc.). See the configure.ac file to find the minimum versions of each +of these tools. You will also need a copy of wget and gnulib. + +When building from Git you must build in the source directory: "VPATH +builds" from remote directories are not supported. Once you've created +a distribution, of course, you can unpack it and do a VPATH build from +there. + +After checking out the code, you will need to perform these steps to get +to the point where you can run "make". + + 1) $ autoreconf -i + + This rebuilds all the things that need rebuilding, installing + missing files as symbolic links. + + You may get warnings here about missing files like README, etc. + Ignore them, they are harmless. + + 2) $ ./configure + + Generate a Makefile + + 3) $ make update + + Use wget to retrieve various other files that GNU make relies on, + but does not keep in its own source tree. + + NB: You may need GNU make to correctly perform this step; if you use + a platform-local make you may get problems with missing files in doc/. + +At this point you have successfully brought your Git copy of the GNU +make source directory up to the point where it can be treated +more-or-less like the official package you would get from ftp.gnu.org. +That is, you can just run: + + $ make && make check && make install + +to build and install GNU make. + + +Windows builds from Git +----------------------- + +If you have a UNIX emulation like CYGWIN you can opt to run the general +build procedure above; it will work. Be sure to read +README.W32.template for information on options you might want to use +when running ./configure. + +If you can't or don't want to do that, then rename the file +README.W32.template to README.W32 and follow those instructions. + + +Creating a Package +------------------ + +Once you have performed the above steps (including the configuration and +build) you can create a GNU make package. This is very simple, just +run: + + $ make dist-gzip + +and, if you like: + + $ make dist-bzip2 + +Even better, you should run this: + + $ make distcheck + +Which will build both .gz and .bz2 package files, then unpack them into +a temporary location, try to build them, and repack them, verifying that +everything works, you get the same results, _and_ no extraneous files +are left over after the "distclean" rule--whew!! Now, _that_ is why +converting to Automake is worth the trouble! A big "huzzah!" to Tom +T. and the AutoToolers! + + +Steps to Release +---------------- + +Here are the things that need to be done (in more or less this order) +before making an official release. If something breaks such that you need to +change code, be sure to start over again sufficiently that everything is +consistent (that's why we don't finalize the Git tag, etc. until the end). + + * Update the configure.ac file with the new release number. + * Update the EDITION value in the doc/make.texi file. + * Update the NEWS file with the release number and date. + * Ensure the Savannah bug list URL in the NEWS file uses the correct + "Fixed Release" ID number. + * Run "make distcheck" to be sure it all works. + * Run "make check-alt-config" to be sure alternative configurations work + * Run "make update-makeweb" to get a copy of the GNU make web pages + * Run "make update-gnuweb" to get a copy of the GNU website boilerplate pages + * Update the web page boilerplate if necessary: + ../gnu-www/www/server/standards/patch-from-parent ../make-web/make.html \ + ../gnu-www/www/server/standards/boilerplate.html + * Run "make gendocs" (requires gnulib) to generate the manual files for + the GNU make web pages. + * Follow the directions from gendocs for the web page repository + * run "make tag-release" to create a Git tag for the release + * Push everything: + git push --tags origin master + +Manage the Savannah project for GNU make: + + >>> This is only for real releases, not release candidate builds <<< + + * In Savannah modify the "Value", "Rank", and "Description" values for the + current "SCM" entry in both "Component Version" and "Fix Release" fields + to refer to the new release. The "Rank" field should be 10 less than the + previous release so it orders properly. + * In Savannah create a new entry for the "Component Version" and "Fix + Release" fields: + - Value: SCM + - Rank: 20 + - Descr: Issues found in code retrieved from Source Code Management (Git), rather than a distributed version. Please include the SHA you are working with. + + - Descr: Fixed in Source Code Management (Git). The fix will be included in the next release of GNU make. + +Start the next release: + + * Update configure.ac and add a ".90" to the release number. + * Update the NEWS file with a new section for the release / date. + * Update the Savannah URL for the bugs fixed in the NEWS section. + + +Publishing a Package +-------------------- + +In order to publish a package on the FSF FTP site, either the release +site ftp://ftp.gnu.org, or the prerelease site ftp://alpha.gnu.org, you +first need to have my GPG private key and my passphrase to unlock it. +And, you can't have them! So there! But, just so I remember here's +what to do: + + Make sure the "Steps to Release" are complete and committed and tagged. + + git clone git://git.savannah.gnu.org/make.git make-release + + cd make-release + + + + make upload-alpha # for alpha.gnu.org (pre-releases) + -OR- + make upload-ftp # for ftp.gnu.org (official releases) + +Depending on your distribution (whether GnuPG is integrated with your keyring +etc.) it will either pop up a window asking for your GPG key passphrase one +time, or else it will use the CLI to ask for the GPG passphrase _THREE_ times. +Sigh. + + +For both final releases and pre-releases, send an email with the URL of +the package to the GNU translation robot to allow the translators to +work on it: + + + + +Where to Announce +----------------- + +Create the announcement in a text file, using 'git shortlog', +then sign it with GPG: + + gpg --clearsign + +Or, use your mail client's PGP/GPG signing capabilities. + +Announce the release: + + * For release candidate builds: + To: bug-make@gnu.org + CC: coordinator@translationproject.org + BCC: help-make@gnu.org, make-w32@gnu.org, make-alpha@gnu.org + + * For release builds + To: info-gnu@gnu.org, bug-make@gnu.org + CC: coordinator@translationproject.org + BCC: help-make@gnu.org, make-w32@gnu.org, make-alpha@gnu.org + + * Add a news item to the Savannah project site. + * Add an update to freecode.com (nee freshmeat.net) + + +Appendix A - For The Brave +-------------------------- + +For those of you who trust me implicitly, or are just brave (or +foolhardy), here is a canned sequence of commands to build a GNU make +distribution package from a virgin Git source checkout (assuming all the +prerequisites are available of course). + +This list is eminently suitable for a quick swipe o' the mouse and a +swift click o' mouse-2 into an xterm. Go for it! + +autoreconf -i +./configure +make update +make +make check + +Or, for a debugging version: + +autoreconf -i && ./configure CFLAGS=-g && make update && make && make check + +Or, all-in-one: + +autoreconf -i && ./configure && make update && make && make check diff --git a/src/kmk/README.template b/src/kmk/README.template new file mode 100644 index 0000000..7739faa --- /dev/null +++ b/src/kmk/README.template @@ -0,0 +1,178 @@ +This directory contains the %VERSION% release of GNU Make. + +See the file NEWS for the user-visible changes from previous releases. +In addition, there have been bugs fixed. + +Please check the system-specific notes below for any caveats related to +your operating system. + +For general building and installation instructions, see the file INSTALL. + +If you need to build GNU Make and have no other 'make' program to use, +you can use the shell script 'build.sh' instead. To do this, first run +'configure' as described in INSTALL. Then, instead of typing 'make' to +build the program, type 'sh build.sh'. This should compile the program +in the current directory. Then you will have a Make program that you can +use for './make install', or whatever else. + +Some systems' Make programs are broken and cannot process the Makefile for +GNU Make. If you get errors from your system's Make when building GNU +Make, try using 'build.sh' instead. + + +GNU Make is free software. See the file COPYING for copying conditions. +GNU Make is copyright by the Free Software Foundation. Copyright notices +condense sequential years into a range; e.g. "1987-1994" means all years +from 1987 to 1994 inclusive. + +Downloading +----------- + +GNU Make can be obtained in many different ways. See a description here: + + http://www.gnu.org/software/software.html + + +Documentation +------------- + +GNU make is fully documented in the GNU Make manual, which is contained +in this distribution as the file make.texinfo. You can also find +on-line and preformatted (PostScript and DVI) versions at the FSF's web +site. There is information there about ordering hardcopy documentation. + + http://www.gnu.org/ + http://www.gnu.org/doc/doc.html + http://www.gnu.org/manual/manual.html + + +Development +----------- + +GNU Make development is hosted by Savannah, the FSF's online development +management tool. Savannah is here: + + http://savannah.gnu.org + +And the GNU Make development page is here: + + http://savannah.gnu.org/projects/make/ + +You can find most information concerning the development of GNU Make at +this site. + + +Bug Reporting +------------- + +You can send GNU make bug reports to . Please see the +section of the GNU make manual entitled 'Problems and Bugs' for +information on submitting useful and complete bug reports. + +You can also use the online bug tracking system in the Savannah GNU Make +project to submit new problem reports or search for existing ones: + + http://savannah.gnu.org/bugs/?group=make + +If you need help using GNU make, try these forums: + + help-make@gnu.org + help-utils@gnu.org + news:gnu.utils.help + news:gnu.utils.bug + + +Git Access +---------- + +The GNU make source repository is available via Git from the +GNU Savannah Git server; look here for details: + + http://savannah.gnu.org/git/?group=make + +Please note: you won't be able to build GNU make from Git without +installing appropriate maintainer's tools, such as GNU m4, automake, +autoconf, Perl, GNU make, and GCC. See the README.git file for hints on +how to build GNU make once these tools are available. We make no +guarantees about the contents or quality of the latest code in the Git +repository: it is not unheard of for code that is known to be broken to +be checked in. Use at your own risk. + + +System-specific Notes +--------------------- + +It has been reported that the XLC 1.2 compiler on AIX 3.2 is buggy such +that if you compile make with 'cc -O' on AIX 3.2, it will not work +correctly. It is said that using 'cc' without '-O' does work. + +The standard /bin/sh on SunOS 4.1.3_U1 and 4.1.4 is broken and cannot be +used to configure GNU make. Please install a different shell such as +bash or pdksh in order to run "configure". See this message for more +information: + http://mail.gnu.org/archive/html/bug-autoconf/2003-10/msg00190.html + +One area that is often a problem in configuration and porting is the code +to check the system's current load average. To make it easier to test and +debug this code, you can do 'make check-loadavg' to see if it works +properly on your system. (You must run 'configure' beforehand, but you +need not build Make itself to run this test.) + +Another potential source of porting problems is the support for large +files (LFS) in configure for those operating systems that provide it. +Please report any bugs that you find in this area. If you run into +difficulties, then as a workaround you should be able to disable LFS by +adding the '--disable-largefile' option to the 'configure' script. + +On systems that support micro- and nano-second timestamp values and +where stat(2) provides this information, GNU make will use it when +comparing timestamps to get the most accurate possible result. However, +note that many current implementations of tools that *set* timestamps do +not preserve micro- or nano-second granularity. This means that "cp -p" +and other similar tools (tar, etc.) may not exactly duplicate timestamps +with micro- and nano-second granularity on some systems. If your build +system contains rules that depend on proper behavior of tools like "cp +-p", you should consider using the .LOW_RESOLUTION_TIME pseudo-target to +force make to treat them properly. See the manual for details. + + +Ports +----- + + - See README.customs for details on integrating GNU make with the + Customs distributed build environment from the Pmake distribution. + + - See README.VMS for details about GNU Make on OpenVMS. + + - See README.Amiga for details about GNU Make on AmigaDOS. + + - See README.W32 for details about GNU Make on Windows NT, 95, or 98. + + - See README.DOS for compilation instructions on MS-DOS and MS-Windows + using DJGPP tools. + + A precompiled binary of the MSDOS port of GNU Make is available as part + of DJGPP; see the WWW page http://www.delorie.com/djgpp/ for more + information. + +Please note there are two _separate_ ports of GNU make for Microsoft +systems: a native Windows tool built with (for example) MSVC or Cygwin, +and a DOS-based tool built with DJGPP. Please be sure you are looking +at the right README! + + +------------------------------------------------------------------------------- +Copyright (C) 1988-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . diff --git a/src/kmk/SCOPTIONS b/src/kmk/SCOPTIONS new file mode 100644 index 0000000..f89daae --- /dev/null +++ b/src/kmk/SCOPTIONS @@ -0,0 +1,13 @@ +ERRORREXX +OPTIMIZE +NOVERSION +OPTIMIZERTIME +OPTIMIZERALIAS +DEFINE INCLUDEDIR="include:" +DEFINE LIBDIR="lib:" +DEFINE NO_ALLOCA +DEFINE NO_FLOAT +DEFINE NO_ARCHIVES +IGNORE=161 +IGNORE=100 +STARTUP=cres diff --git a/src/kmk/SMakefile.template b/src/kmk/SMakefile.template new file mode 100644 index 0000000..1b60d85 --- /dev/null +++ b/src/kmk/SMakefile.template @@ -0,0 +1,218 @@ +# -*-Makefile-*- for building GNU make with smake +# +# NOTE: If you have no 'make' program at all to process this makefile, +# run 'build.sh' instead. +# +# Copyright (C) 1995-2016 Free Software Foundation, Inc. +# This file is part of GNU Make. +# +# GNU Make is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +# +# Makefile for GNU Make +# + +# Ultrix 2.2 make doesn't expand the value of VPATH. +VPATH = /make-%VERSION%/ +# This must repeat the value, because configure will remove 'VPATH = .'. +srcdir = /make-%VERSION%/ + +CC = sc +RM = delete +MAKE = smake + +CFLAGS = +CPPFLAGS = +LDFLAGS = + +# Define these for your system as follows: +# -DNO_ARCHIVES To disable 'ar' archive support. +# -DNO_FLOAT To avoid using floating-point numbers. +# -DENUM_BITFIELDS If the compiler isn't GCC but groks enum foo:2. +# Some compilers apparently accept this +# without complaint but produce losing code, +# so beware. +# NeXT 1.0a uses an old version of GCC, which required -D__inline=inline. +# See also 'config.h'. +defines = + +# Which flavor of remote job execution support to use. +# The code is found in 'remote-$(REMOTE).c'. +REMOTE = stub + +# If you are using the GNU C library, or have the GNU getopt functions in +# your C library, you can comment these out. +GETOPT = getopt.o getopt1.o +GETOPT_SRC = $(srcdir)getopt.c $(srcdir)getopt1.c $(srcdir)getopt.h + +# If you are using the GNU C library, or have the GNU glob functions in +# your C library, you can comment this out. GNU make uses special hooks +# into the glob functions to be more efficient (by using make's directory +# cache for globbing), so you must use the GNU functions even if your +# system's C library has the 1003.2 glob functions already. Also, the glob +# functions in the AIX and HPUX C libraries are said to be buggy. +GLOB = Lib glob/glob.lib + +# If your system doesn't have alloca, or the one provided is bad, define this. +ALLOCA = alloca.o +ALLOCA_SRC = $(srcdir)alloca.c + +# If your system needs extra libraries loaded in, define them here. +# System V probably need -lPW for alloca. HP-UX 7.0's alloca in +# libPW.a is broken on HP9000s300 and HP9000s400 machines. Use +# alloca.c instead on those machines. +LOADLIBES = + +# Any extra object files your system needs. +extras = amiga.o + +# Common prefix for machine-independent installed files. +prefix = +# Common prefix for machine-dependent installed files. +exec_prefix = + +# Directory to install 'make' in. +bindir = sc:c +# Directory to find libraries in for '-lXXX'. +libdir = lib: +# Directory to search by default for included makefiles. +includedir = include: +# Directory to install the Info files in. +infodir = doc: +# Directory to install the man page in. +mandir = t: +# Number to put on the man page filename. +manext = 1 +# Prefix to put on installed 'make' binary file name. +binprefix = +# Prefix to put on installed 'make' man page file name. +manprefix = $(binprefix) + +# Whether or not make needs to be installed setgid. +# The value should be either 'true' or 'false'. +# On many systems, the getloadavg function (used to implement the '-l' +# switch) will not work unless make is installed setgid kmem. +install_setgid = false +# Install make setgid to this group so it can read /dev/kmem. +group = sys + +# Program to install 'make'. +INSTALL_PROGRAM = copy +# Program to install the man page. +INSTALL_DATA = copy +# Generic install program. +INSTALL = copy + +# Program to format Texinfo source into Info files. +MAKEINFO = makeinfo +# Program to format Texinfo source into DVI files. +TEXI2DVI = texi2dvi + +# Programs to make tags files. +ETAGS = etags -w +CTAGS = ctags -w + +#guile = guile.o + +objs = commands.o job.o dir.o file.o misc.o main.o read.o remake.o \ + rule.o implicit.o default.o variable.o expand.o function.o \ + vpath.o version.o ar.o arscan.o signame.o strcache.o hash.o \ + output.o remote-$(REMOTE).o $(GLOB) $(GETOPT) $(ALLOCA) \ + $(extras) $(guile) + +srcs = $(srcdir)commands.c $(srcdir)job.c $(srcdir)dir.c \ + $(srcdir)file.c $(srcdir)getloadavg.c $(srcdir)misc.c \ + $(srcdir)main.c $(srcdir)read.c $(srcdir)remake.c \ + $(srcdir)rule.c $(srcdir)implicit.c $(srcdir)default.c \ + $(srcdir)variable.c $(srcdir)expand.c $(srcdir)function.c \ + $(srcdir)vpath.c $(srcdir)version.c $(srcdir)hash.c \ + $(srcdir)guile.c $(srcdir)remote-$(REMOTE).c \ + $(srcdir)ar.c $(srcdir)arscan.c $(srcdir)strcache.c \ + $(srcdir)signame.c $(srcdir)signame.h $(GETOPT_SRC) \ + $(srcdir)commands.h $(srcdir)dep.h $(srcdir)file.h \ + $(srcdir)job.h $(srcdir)makeint.h $(srcdir)rule.h \ + $(srcdir)output.c $(srcdir)output.h \ + $(srcdir)variable.h $(ALLOCA_SRC) $(srcdir)config.h.in + + +.SUFFIXES: +.SUFFIXES: .o .c .h .ps .dvi .info .texinfo + +all: make +info: make.info +dvi: make.dvi +# Some makes apparently use .PHONY as the default goal if it is before 'all'. +.PHONY: all check info dvi + +make.info: make.texinfo + $(MAKEINFO) -I$(srcdir) $(srcdir)make.texinfo -o make.info + +make.dvi: make.texinfo + $(TEXI2DVI) $(srcdir)make.texinfo + +make.ps: make.dvi + dvi2ps make.dvi > make.ps + +make: $(objs) glob/glob.lib + $(CC) Link $(LDFLAGS) $(objs) $(LOADLIBES) To make.new + -delete quiet make + rename make.new make + +# -I. is needed to find config.h in the build directory. +.c.o: + $(CC) $(defines) IDir "" IDir $(srcdir)glob \ + $(CPPFLAGS) $(CFLAGS) $< $(OUTPUT_OPTION) + +glob/glob.lib: + execute << + cd glob + smake +< + +tagsrcs = $(srcs) $(srcdir)remote-*.c +TAGS: $(tagsrcs) + $(ETAGS) $(tagsrcs) +tags: $(tagsrcs) + $(CTAGS) $(tagsrcs) + +.PHONY: install installdirs +install: + copy make sc:c + +loadavg: loadavg.c config.h + $(CC) $(defines) -DTEST -I. -I$(srcdir) $(CFLAGS) $(LDFLAGS) \ + loadavg.c $(LOADLIBES) -o $@ + +clean: glob-clean + -$(RM) -f make loadavg *.o core make.dvi + +distclean: clean glob-realclean + -$(RM) -f Makefile config.h config.status build.sh + -$(RM) -f config.log config.cache + -$(RM) -f TAGS tags + -$(RM) -f make.?? make.??s make.log make.toc make.*aux + -$(RM) -f loadavg.c + +realclean: distclean + -$(RM) -f make.info* + +mostlyclean: clean + +.PHONY: glob-clean glob-realclean + +glob-clean glob-realclean: + execute << + cd glob + smake $@ +< diff --git a/src/kmk/TODO.private b/src/kmk/TODO.private new file mode 100644 index 0000000..a56827a --- /dev/null +++ b/src/kmk/TODO.private @@ -0,0 +1,117 @@ + -*-Indented-Text-*- +GNU Make TODO List +------------------ + +This list comes both from the authors and from users of GNU make. + +They are listed in no particular order! + +Also, I don't guarantee that all of them will be ultimately deemed "good +ideas" and implemented. These are just the ones that, at first blush, +seem to have some merit (and that I can remember). + +However, if you see something here you really, really want, speak up. +All other things being equal, I will tend to implement things that seem +to maximize user satisfaction. + +If you want to implement some of them yourself, barring the ones I've +marked below, have at it! Please contact me first to let me know you're +working on it, and give me some info about the design--and, critically, +information about any user-visible syntax change, etc. + + +The Top Item +------------ + +If you know perl (or want to learn DejaGNU or similar), the number one +priority on my list of things I don't have time to do right now is +fixing up the GNU make test suite. Most importantly it needs to be made +"parallelizable", so more than one regression can run at the same time +(essentially, make the "work" directory local). Also, the CWD during +the test should be in the work directory or, better, a test-specific +temporary directory so each test gets a new directory; right now +sometimes tests leak files into the main directory which causes +subsequent tests to fail (some tests may need to be tweaked). Beyond +that, any cleanup done to make writing, reading, or handling tests +simpler would be great! Please feel free to make whatever changes you +like to the current tests, given some high-level goals, and that you'll +port the current tests to whatever you do :). + + +The Rest of the List +-------------------- + + 1) Option to check more than timestamps to determine if targets have + changed. This is also a very big one. It's _close_ to my plate :), + and I have very definite ideas about how I would like it done. + Please pick something else unless you must have this feature. If + you try it, please work _extremely_ closely with me on it. + + 1a) Possibly a special case of this is the .KEEP_STATE feature of Sun's + make. Some great folks at W U. in Canada did an implementation of + this for a class project. Their approach is reasonable and + workable, but doesn't really fit into my ideas for #2. Maybe + that's OK. I have paperwork for their work so if you want to do + this one talk to me to get what they've already done. + + [K R Praveen ] + + 2) Currently you can use "%.foo %.bar : %.baz" to mean that one + invocation of the rule builds both targets. GNU make needs a way to + do that for explicit rules, too. I heard a rumor that some versions + of make all you to say "a.foo + a.bar : a.baz" to do this (i.e., a + "+" means one invocation builds both). Don't know if this is the + best syntax or not... what if you say "a.foo + a.bar a.bam : a.baz"; + what does that mean? + + 3) Multi-token pattern rule matching (allow %1/%2.c : %1/obj/%2.o, + etc., or something like that). Maybe using regex? + + 4) Provide a .TARGETS variable, containing the names of the targets + defined in the makefile. + + Actually, I now think a $(targets ...) function, at least, might be + better than a MAKETARGETS variable. The argument would be types of + targets to list: "phony" is the most useful one. I suppose + "default" might also be useful. Maybe some others; check the + bitfields to see what might be handy. + + 5) Some sort of operating-system independent way of handling paths + would be outstanding, so makefiles can be written for UNIX, VMS, + DOS, MS-Windows, Amiga, etc. with a minimum of specialization. + + Or, perhaps related/instead of, some sort of meta-quoting syntax so + make can deal with filenames containing spaces, colons, etc. I + dunno, maybe something like $[...]? This may well not be worth + doing until #1 is done. + + 6) Right now the .PRECIOUS, .INTERMEDIATE, and .SECONDARY + pseudo-targets have different capabilities. For example, .PRECIOUS + can take a "%", the others can't. Etc. These should all work the + same, insofar as that makes sense. + + 7) Improved debugging/logging/etc. capabilities. Part of this is done: + I introduced a number of debugging enhancements. Tim Magill is (I + think) looking into options to control output more selectively. + One thing I want to do in debugging is add a flag to allow debugging + of variables as they're expanded (!). This would be incredibly + verbose, but could be invaluable when nothing else seems to work and + you just can't figure it out. The way variables are expanded now + means this isn't 100% trivial, but it probably won't be hard. + + +------------------------------------------------------------------------------- +Copyright (C) 1997-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . diff --git a/src/kmk/acinclude.m4 b/src/kmk/acinclude.m4 new file mode 100644 index 0000000..a80bcb3 --- /dev/null +++ b/src/kmk/acinclude.m4 @@ -0,0 +1,163 @@ +dnl acinclude.m4 -- Extra macros needed for GNU make. +dnl +dnl Automake will incorporate this into its generated aclocal.m4. +dnl Copyright (C) 1998-2016 Free Software Foundation, Inc. +dnl This file is part of GNU Make. +dnl +dnl GNU Make is free software; you can redistribute it and/or modify it under +dnl the terms of the GNU General Public License as published by the Free +dnl Software Foundation; either version 3 of the License, or (at your option) +dnl any later version. +dnl +dnl GNU Make is distributed in the hope that it will be useful, but WITHOUT +dnl ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for. +dnl more details. +dnl +dnl You should have received a copy of the GNU General Public License along +dnl with this program. If not, see . + +dnl --------------------------------------------------------------------------- +dnl Got this from the lynx 2.8 distribution. +dnl by T.E.Dickey +dnl and Jim Spath +dnl and Philippe De Muyter +dnl +dnl Created: 1997/1/28 +dnl Updated: 1997/12/23 +dnl --------------------------------------------------------------------------- +dnl After checking for functions in the default $LIBS, make a further check +dnl for the functions that are netlib-related (these aren't always in the +dnl libc, etc., and have to be handled specially because there are conflicting +dnl and broken implementations. +dnl Common library requirements (in order): +dnl -lresolv -lsocket -lnsl +dnl -lnsl -lsocket +dnl -lsocket +dnl -lbsd +AC_DEFUN([CF_NETLIBS],[ +cf_test_netlibs=no +AC_MSG_CHECKING(for network libraries) +AC_CACHE_VAL(cf_cv_netlibs,[ +AC_MSG_RESULT(working...) +cf_cv_netlibs="" +cf_test_netlibs=yes +AC_CHECK_FUNCS(gethostname,,[ + CF_RECHECK_FUNC(gethostname,nsl,cf_cv_netlibs,[ + CF_RECHECK_FUNC(gethostname,socket,cf_cv_netlibs)])]) +# +# FIXME: sequent needs this library (i.e., -lsocket -linet -lnsl), but +# I don't know the entrypoints - 97/7/22 TD +AC_CHECK_LIB(inet,main,cf_cv_netlibs="-linet $cf_cv_netlibs") +# +if test "$ac_cv_func_lsocket" != no ; then +AC_CHECK_FUNCS(socket,,[ + CF_RECHECK_FUNC(socket,socket,cf_cv_netlibs,[ + CF_RECHECK_FUNC(socket,bsd,cf_cv_netlibs)])]) +fi +# +AC_CHECK_FUNCS(gethostbyname,,[ + CF_RECHECK_FUNC(gethostbyname,nsl,cf_cv_netlibs)]) +]) +LIBS="$LIBS $cf_cv_netlibs" +test $cf_test_netlibs = no && echo "$cf_cv_netlibs" >&AC_FD_MSG +])dnl +dnl --------------------------------------------------------------------------- +dnl Re-check on a function to see if we can pick it up by adding a library. +dnl $1 = function to check +dnl $2 = library to check in +dnl $3 = environment to update (e.g., $LIBS) +dnl $4 = what to do if this fails +dnl +dnl This uses 'unset' if the shell happens to support it, but leaves the +dnl configuration variable set to 'unknown' if not. This is a little better +dnl than the normal autoconf test, which gives misleading results if a test +dnl for the function is made (e.g., with AC_CHECK_FUNC) after this macro is +dnl used (autoconf does not distinguish between a null token and one that is +dnl set to 'no'). +AC_DEFUN([CF_RECHECK_FUNC],[ +AC_CHECK_LIB($2,$1,[ + CF_UPPER(cf_tr_func,$1) + AC_DEFINE_UNQUOTED(HAVE_$cf_tr_func,1,[Define if you have function $1]) + ac_cv_func_$1=yes + $3="-l$2 [$]$3"],[ + ac_cv_func_$1=unknown + unset ac_cv_func_$1 2>/dev/null + $4], + [[$]$3]) +])dnl +dnl --------------------------------------------------------------------------- +dnl Make an uppercase version of a variable +dnl $1=uppercase($2) +AC_DEFUN([CF_UPPER], +[ +changequote(,)dnl +$1=`echo $2 | tr '[a-z]' '[A-Z]'` +changequote([,])dnl +])dnl + + +dnl --------------------------------------------------------------------------- +dnl From Paul Eggert +dnl Update for Darwin by Troy Runkel +dnl Update for AIX by Olexiy Buyanskyy (Savannah bug 32485) + +AC_DEFUN([AC_STRUCT_ST_MTIM_NSEC], + [AC_CACHE_CHECK([for nanoseconds field of struct stat], + ac_cv_struct_st_mtim_nsec, + [ac_save_CPPFLAGS="$CPPFLAGS" + ac_cv_struct_st_mtim_nsec=no + # st_mtim.tv_nsec -- the usual case + # st_mtim._tv_nsec -- Solaris 2.6, if + # (defined _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED == 1 + # && !defined __EXTENSIONS__) + # st_mtim.st__tim.tv_nsec -- UnixWare 2.1.2 + # st_mtime_n -- AIX 5.2 and above + # st_mtimespec.tv_nsec -- Darwin (Mac OSX) + for ac_val in st_mtim.tv_nsec st_mtim._tv_nsec st_mtim.st__tim.tv_nsec st_mtime_n st_mtimespec.tv_nsec; do + CPPFLAGS="$ac_save_CPPFLAGS -DST_MTIM_NSEC=$ac_val" + AC_TRY_COMPILE([#include +#include + ], [struct stat s; s.ST_MTIM_NSEC;], + [ac_cv_struct_st_mtim_nsec=$ac_val; break]) + done + CPPFLAGS="$ac_save_CPPFLAGS" + ]) + + if test $ac_cv_struct_st_mtim_nsec != no; then + AC_DEFINE_UNQUOTED([ST_MTIM_NSEC], [$ac_cv_struct_st_mtim_nsec], + [Define if struct stat contains a nanoseconds field]) + fi + ] +) + +dnl bird: Copy of above for atime +AC_DEFUN([AC_STRUCT_ST_ATIM_NSEC], + [AC_CACHE_CHECK([for nanoseconds access time field of struct stat], + ac_cv_struct_st_atim_nsec, + [ac_save_CPPFLAGS="$CPPFLAGS" + ac_cv_struct_st_atim_nsec=no + # st_atim.tv_nsec -- the usual case + # st_atim._tv_nsec -- Solaris 2.6, if + # (defined _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED == 1 + # && !defined __EXTENSIONS__) + # st_atim.st__tim.tv_nsec -- UnixWare 2.1.2 + # st_atime_n -- AIX 5.2 and above + # st_atimespec.tv_nsec -- Darwin (Mac OSX) + for ac_val in st_atim.tv_nsec st_atim._tv_nsec st_atim.st__tim.tv_nsec st_atime_n st_atimespec.tv_nsec; do + CPPFLAGS="$ac_save_CPPFLAGS -DST_ATIM_NSEC=$ac_val" + AC_TRY_COMPILE([#include +#include + ], [struct stat s; s.ST_ATIM_NSEC;], + [ac_cv_struct_st_atim_nsec=$ac_val; break]) + done + CPPFLAGS="$ac_save_CPPFLAGS" + ]) + + if test $ac_cv_struct_st_atim_nsec != no; then + AC_DEFINE_UNQUOTED([ST_ATIM_NSEC], [$ac_cv_struct_st_atim_nsec], + [Define if struct stat contains a nanoseconds field]) + fi + ] +) + diff --git a/src/kmk/alloca.c b/src/kmk/alloca.c new file mode 100644 index 0000000..02ac921 --- /dev/null +++ b/src/kmk/alloca.c @@ -0,0 +1,503 @@ +/* alloca.c -- allocate automatically reclaimed memory + (Mostly) portable public-domain implementation -- D A Gwyn + + This implementation of the PWB library alloca function, + which is used to allocate space off the run-time stack so + that it is automatically reclaimed upon procedure exit, + was inspired by discussions with J. Q. Johnson of Cornell. + J.Otto Tennant contributed the Cray support. + + There are some preprocessor constants that can + be defined when compiling for your specific system, for + improved efficiency; however, the defaults should be okay. + + The general concept of this implementation is to keep + track of all alloca-allocated blocks, and reclaim any + that are found to be deeper in the stack than the current + invocation. This heuristic does not reclaim storage as + soon as it becomes invalid, but it will do so eventually. + + As a special case, alloca(0) reclaims storage without + allocating any. It is a good idea to use alloca(0) in + your main control loop, etc. to force garbage collection. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef emacs +#include "blockinput.h" +#endif + +/* If compiling with GCC 2, this file's not needed. */ +#if !defined (__GNUC__) || __GNUC__ < 2 + +/* If someone has defined alloca as a macro, + there must be some other way alloca is supposed to work. */ +#ifndef alloca + +#ifdef emacs +#ifdef static +/* actually, only want this if static is defined as "" + -- this is for usg, in which emacs must undefine static + in order to make unexec workable + */ +#ifndef STACK_DIRECTION +you +lose +-- must know STACK_DIRECTION at compile-time +#endif /* STACK_DIRECTION undefined */ +#endif /* static */ +#endif /* emacs */ + +/* If your stack is a linked list of frames, you have to + provide an "address metric" ADDRESS_FUNCTION macro. */ + +#if defined (CRAY) && defined (CRAY_STACKSEG_END) +long i00afunc (); +#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg)) +#else +#define ADDRESS_FUNCTION(arg) &(arg) +#endif + +#if __STDC__ +typedef void *pointer; +#else +typedef char *pointer; +#endif + +#ifndef NULL +#define NULL 0 +#endif + +/* Different portions of Emacs need to call different versions of + malloc. The Emacs executable needs alloca to call xmalloc, because + ordinary malloc isn't protected from input signals. On the other + hand, the utilities in lib-src need alloca to call malloc; some of + them are very simple, and don't have an xmalloc routine. + + Non-Emacs programs expect this to call use xmalloc. + + Callers below should use malloc. */ + +#ifndef emacs +#define malloc xmalloc +#endif +extern pointer malloc (); + +/* Define STACK_DIRECTION if you know the direction of stack + growth for your system; otherwise it will be automatically + deduced at run-time. + + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ + +#ifndef STACK_DIRECTION +#define STACK_DIRECTION 0 /* Direction unknown. */ +#endif + +#if STACK_DIRECTION != 0 + +#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */ + +#else /* STACK_DIRECTION == 0; need run-time code. */ + +static int stack_dir; /* 1 or -1 once known. */ +#define STACK_DIR stack_dir + +static void +find_stack_direction (void) +{ + static char *addr = NULL; /* Address of first 'dummy', once known. */ + auto char dummy; /* To get stack address. */ + + if (addr == NULL) + { /* Initial entry. */ + addr = ADDRESS_FUNCTION (dummy); + + find_stack_direction (); /* Recurse once. */ + } + else + { + /* Second entry. */ + if (ADDRESS_FUNCTION (dummy) > addr) + stack_dir = 1; /* Stack grew upward. */ + else + stack_dir = -1; /* Stack grew downward. */ + } +} + +#endif /* STACK_DIRECTION == 0 */ + +/* An "alloca header" is used to: + (a) chain together all alloca'ed blocks; + (b) keep track of stack depth. + + It is very important that sizeof(header) agree with malloc + alignment chunk size. The following default should work okay. */ + +#ifndef ALIGN_SIZE +#define ALIGN_SIZE sizeof(double) +#endif + +typedef union hdr +{ + char align[ALIGN_SIZE]; /* To force sizeof(header). */ + struct + { + union hdr *next; /* For chaining headers. */ + char *deep; /* For stack depth measure. */ + } h; +} header; + +static header *last_alloca_header = NULL; /* -> last alloca header. */ + +/* Return a pointer to at least SIZE bytes of storage, + which will be automatically reclaimed upon exit from + the procedure that called alloca. Originally, this space + was supposed to be taken from the current stack frame of the + caller, but that method cannot be made to work for some + implementations of C, for example under Gould's UTX/32. */ + +pointer +alloca (unsigned size) +{ + auto char probe; /* Probes stack depth: */ + register char *depth = ADDRESS_FUNCTION (probe); + +#if STACK_DIRECTION == 0 + if (STACK_DIR == 0) /* Unknown growth direction. */ + find_stack_direction (); +#endif + + /* Reclaim garbage, defined as all alloca'd storage that + was allocated from deeper in the stack than currently. */ + + { + register header *hp; /* Traverses linked list. */ + +#ifdef emacs + BLOCK_INPUT; +#endif + + for (hp = last_alloca_header; hp != NULL;) + if ((STACK_DIR > 0 && hp->h.deep > depth) + || (STACK_DIR < 0 && hp->h.deep < depth)) + { + register header *np = hp->h.next; + + free ((pointer) hp); /* Collect garbage. */ + + hp = np; /* -> next header. */ + } + else + break; /* Rest are not deeper. */ + + last_alloca_header = hp; /* -> last valid storage. */ + +#ifdef emacs + UNBLOCK_INPUT; +#endif + } + + if (size == 0) + return NULL; /* No allocation required. */ + + /* Allocate combined header + user data storage. */ + + { + register pointer new = malloc (sizeof (header) + size); + /* Address of header. */ + + if (new == 0) + abort(); + + ((header *) new)->h.next = last_alloca_header; + ((header *) new)->h.deep = depth; + + last_alloca_header = (header *) new; + + /* User storage begins just after header. */ + + return (pointer) ((char *) new + sizeof (header)); + } +} + +#if defined (CRAY) && defined (CRAY_STACKSEG_END) + +#ifdef DEBUG_I00AFUNC +#include +#endif + +#ifndef CRAY_STACK +#define CRAY_STACK +#ifndef CRAY2 +/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */ +struct stack_control_header + { + long shgrow:32; /* Number of times stack has grown. */ + long shaseg:32; /* Size of increments to stack. */ + long shhwm:32; /* High water mark of stack. */ + long shsize:32; /* Current size of stack (all segments). */ + }; + +/* The stack segment linkage control information occurs at + the high-address end of a stack segment. (The stack + grows from low addresses to high addresses.) The initial + part of the stack segment linkage control information is + 0200 (octal) words. This provides for register storage + for the routine which overflows the stack. */ + +struct stack_segment_linkage + { + long ss[0200]; /* 0200 overflow words. */ + long sssize:32; /* Number of words in this segment. */ + long ssbase:32; /* Offset to stack base. */ + long:32; + long sspseg:32; /* Offset to linkage control of previous + segment of stack. */ + long:32; + long sstcpt:32; /* Pointer to task common address block. */ + long sscsnm; /* Private control structure number for + microtasking. */ + long ssusr1; /* Reserved for user. */ + long ssusr2; /* Reserved for user. */ + long sstpid; /* Process ID for pid based multi-tasking. */ + long ssgvup; /* Pointer to multitasking thread giveup. */ + long sscray[7]; /* Reserved for Cray Research. */ + long ssa0; + long ssa1; + long ssa2; + long ssa3; + long ssa4; + long ssa5; + long ssa6; + long ssa7; + long sss0; + long sss1; + long sss2; + long sss3; + long sss4; + long sss5; + long sss6; + long sss7; + }; + +#else /* CRAY2 */ +/* The following structure defines the vector of words + returned by the STKSTAT library routine. */ +struct stk_stat + { + long now; /* Current total stack size. */ + long maxc; /* Amount of contiguous space which would + be required to satisfy the maximum + stack demand to date. */ + long high_water; /* Stack high-water mark. */ + long overflows; /* Number of stack overflow ($STKOFEN) calls. */ + long hits; /* Number of internal buffer hits. */ + long extends; /* Number of block extensions. */ + long stko_mallocs; /* Block allocations by $STKOFEN. */ + long underflows; /* Number of stack underflow calls ($STKRETN). */ + long stko_free; /* Number of deallocations by $STKRETN. */ + long stkm_free; /* Number of deallocations by $STKMRET. */ + long segments; /* Current number of stack segments. */ + long maxs; /* Maximum number of stack segments so far. */ + long pad_size; /* Stack pad size. */ + long current_address; /* Current stack segment address. */ + long current_size; /* Current stack segment size. This + number is actually corrupted by STKSTAT to + include the fifteen word trailer area. */ + long initial_address; /* Address of initial segment. */ + long initial_size; /* Size of initial segment. */ + }; + +/* The following structure describes the data structure which trails + any stack segment. I think that the description in 'asdef' is + out of date. I only describe the parts that I am sure about. */ + +struct stk_trailer + { + long this_address; /* Address of this block. */ + long this_size; /* Size of this block (does not include + this trailer). */ + long unknown2; + long unknown3; + long link; /* Address of trailer block of previous + segment. */ + long unknown5; + long unknown6; + long unknown7; + long unknown8; + long unknown9; + long unknown10; + long unknown11; + long unknown12; + long unknown13; + long unknown14; + }; + +#endif /* CRAY2 */ +#endif /* not CRAY_STACK */ + +#ifdef CRAY2 +/* Determine a "stack measure" for an arbitrary ADDRESS. + I doubt that "lint" will like this much. */ + +static long +i00afunc (long *address) +{ + struct stk_stat status; + struct stk_trailer *trailer; + long *block, size; + long result = 0; + + /* We want to iterate through all of the segments. The first + step is to get the stack status structure. We could do this + more quickly and more directly, perhaps, by referencing the + $LM00 common block, but I know that this works. */ + + STKSTAT (&status); + + /* Set up the iteration. */ + + trailer = (struct stk_trailer *) (status.current_address + + status.current_size + - 15); + + /* There must be at least one stack segment. Therefore it is + a fatal error if "trailer" is null. */ + + if (trailer == 0) + abort (); + + /* Discard segments that do not contain our argument address. */ + + while (trailer != 0) + { + block = (long *) trailer->this_address; + size = trailer->this_size; + if (block == 0 || size == 0) + abort (); + trailer = (struct stk_trailer *) trailer->link; + if ((block <= address) && (address < (block + size))) + break; + } + + /* Set the result to the offset in this segment and add the sizes + of all predecessor segments. */ + + result = address - block; + + if (trailer == 0) + { + return result; + } + + do + { + if (trailer->this_size <= 0) + abort (); + result += trailer->this_size; + trailer = (struct stk_trailer *) trailer->link; + } + while (trailer != 0); + + /* We are done. Note that if you present a bogus address (one + not in any segment), you will get a different number back, formed + from subtracting the address of the first block. This is probably + not what you want. */ + + return (result); +} + +#else /* not CRAY2 */ +/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP. + Determine the number of the cell within the stack, + given the address of the cell. The purpose of this + routine is to linearize, in some sense, stack addresses + for alloca. */ + +static long +i00afunc (long address) +{ + long stkl = 0; + + long size, pseg, this_segment, stack; + long result = 0; + + struct stack_segment_linkage *ssptr; + + /* Register B67 contains the address of the end of the + current stack segment. If you (as a subprogram) store + your registers on the stack and find that you are past + the contents of B67, you have overflowed the segment. + + B67 also points to the stack segment linkage control + area, which is what we are really interested in. */ + + stkl = CRAY_STACKSEG_END (); + ssptr = (struct stack_segment_linkage *) stkl; + + /* If one subtracts 'size' from the end of the segment, + one has the address of the first word of the segment. + + If this is not the first segment, 'pseg' will be + nonzero. */ + + pseg = ssptr->sspseg; + size = ssptr->sssize; + + this_segment = stkl - size; + + /* It is possible that calling this routine itself caused + a stack overflow. Discard stack segments which do not + contain the target address. */ + + while (!(this_segment <= address && address <= stkl)) + { +#ifdef DEBUG_I00AFUNC + fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl); +#endif + if (pseg == 0) + break; + stkl = stkl - pseg; + ssptr = (struct stack_segment_linkage *) stkl; + size = ssptr->sssize; + pseg = ssptr->sspseg; + this_segment = stkl - size; + } + + result = address - this_segment; + + /* If you subtract pseg from the current end of the stack, + you get the address of the previous stack segment's end. + This seems a little convoluted to me, but I'll bet you save + a cycle somewhere. */ + + while (pseg != 0) + { +#ifdef DEBUG_I00AFUNC + fprintf (stderr, "%011o %011o\n", pseg, size); +#endif + stkl = stkl - pseg; + ssptr = (struct stack_segment_linkage *) stkl; + size = ssptr->sssize; + pseg = ssptr->sspseg; + result += size; + } + return (result); +} + +#endif /* not CRAY2 */ +#endif /* CRAY */ + +#endif /* no alloca */ +#endif /* not GCC version 2 */ diff --git a/src/kmk/alloccache.c b/src/kmk/alloccache.c new file mode 100644 index 0000000..54c28d5 --- /dev/null +++ b/src/kmk/alloccache.c @@ -0,0 +1,259 @@ +/* $Id: alloccache.c 3141 2018-03-14 21:58:32Z bird $ */ +/** @file + * alloccache - Fixed sized allocation cache. + * + * The rational for using an allocation cache, is that it is way faster + * than malloc+free on most systems. It may be more efficient as well, + * depending on the way the heap implementes small allocations. Also, + * with the incdep.c code being threaded, all heaps (except for MSC) + * ran into severe lock contention issues since both the main thread + * and the incdep worker thread was allocating a crazy amount of tiny + * allocations (struct dep, struct nameseq, ++). + * + * Darwin also showed a significant amount of time spent just executing + * free(), which is kind of silly. The alloccache helps a bit here too. + */ + +/* + * Copyright (c) 2008-2010 knut st. osmundsen + * + * This file is part of kBuild. + * + * kBuild is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * kBuild is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kBuild. If not, see + * + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "makeint.h" +#include "filedef.h" +#include "dep.h" +#include "debug.h" +#include + + +#ifdef CONFIG_WITH_ALLOC_CACHES + +/* Free am item. + This was not inlined because of aliasing issues arrising with GCC. + It is also in a separate file for this reason (it used to be in misc.c + but since free_dep_chain() was using it there, we ran the risk of it + being inlined and gcc screwing up). */ +void +alloccache_free (struct alloccache *cache, void *item) +{ +#ifndef CONFIG_WITH_ALLOCCACHE_DEBUG + struct alloccache_free_ent *f = (struct alloccache_free_ent *)item; +# if 0 /*ndef NDEBUG*/ + struct alloccache_free_ent *c; + unsigned int i = 0; + for (c = cache->free_head; c != NULL; c = c->next, i++) + MY_ASSERT_MSG (c != f && i < 0x10000000, + ("i=%u total_count=%u\n", i, cache->total_count)); +# endif + + f->next = cache->free_head; + cache->free_head = f; + MAKE_STATS(cache->free_count++;); +#else /* CONFIG_WITH_ALLOCCACHE_DEBUG */ + + struct alloccache **ppcache = (struct alloccache **)item - 1; + MY_ASSERT_MSG (*ppcache == cache, ("*ppcache=%p cache=%p item=%p\n", *ppcache, cache, item)); + *ppcache = NULL; + free(ppcache); +#endif /* CONFIG_WITH_ALLOCCACHE_DEBUG */ +} + +/* Default allocator. */ +static void * +alloccache_default_grow_alloc(void *ignore, unsigned int size) +{ + return xmalloc (size); +} + +/* Worker for growing the cache. */ +struct alloccache_free_ent * +alloccache_alloc_grow (struct alloccache *cache) +{ +#ifndef CONFIG_WITH_ALLOCCACHE_DEBUG + void *item; + unsigned int items = (64*1024 - 32) / cache->size; + cache->free_start = cache->grow_alloc (cache->grow_arg, items * cache->size); + cache->free_end = cache->free_start + items * cache->size; + cache->total_count+= items; + +# ifndef NDEBUG /* skip the first item so the heap can detect free(). */ + cache->total_count--; + cache->free_start += cache->size; +# endif + + item = cache->free_start; + cache->free_start += cache->size; + /* caller counts */ + return (struct alloccache_free_ent *)item; +#else /* CONFIG_WITH_ALLOCCACHE_DEBUG */ + + /* Prefix the allocation with a cache pointer so alloccahce_free can better + catch incorrect calls. */ + struct alloccache **ppcache = (struct alloccache **)xmalloc(sizeof(*ppcache) + cache->size); + *ppcache = cache; + return (struct alloccache_free_ent *)(ppcache + 1); +#endif /* CONFIG_WITH_ALLOCCACHE_DEBUG */ +} + +/* List of alloc caches, for printing. */ +static struct alloccache *alloccache_head = NULL; + +/* Initializes an alloc cache */ +void +alloccache_init (struct alloccache *cache, unsigned int size, const char *name, + void *(*grow_alloc)(void *grow_arg, unsigned int size), void *grow_arg) +{ + unsigned act_size; + + /* ensure OK alignment and min sizeof (struct alloccache_free_ent). */ + if (size <= sizeof (struct alloccache_free_ent)) + act_size = sizeof (struct alloccache_free_ent); + else if (size <= 32) + { + act_size = 4; + while (act_size < size) + act_size <<= 1; + } + else + act_size = (size + 31U) & ~(size_t)31; + + /* align the structure. */ + cache->free_start = NULL; + cache->free_end = NULL; + cache->free_head = NULL; + cache->size = act_size; + cache->total_count = 0; + cache->alloc_count = 0; + cache->free_count = 0; + cache->name = name; + cache->grow_arg = grow_arg; + cache->grow_alloc = grow_alloc ? grow_alloc : alloccache_default_grow_alloc; + + /* link it. */ + cache->next = alloccache_head; + alloccache_head = cache; +} + +/* Terminate an alloc cache, free all the memory it contains. */ +void +alloccache_term (struct alloccache *cache, + void (*term_free)(void *term_arg, void *ptr, unsigned int size), void *term_arg) +{ + /*cache->size = 0;*/ + (void)cache; + (void)term_free; + (void)term_arg; + /* FIXME: Implement memory segment tracking and cleanup. */ +} + +/* Joins to caches, unlinking the 2nd one. */ +void +alloccache_join (struct alloccache *cache, struct alloccache *eat) +{ + assert (cache->size == eat->size); + +#if 0 /* probably a waste of time */ /* FIXME: Optimize joining, avoid all list walking. */ + /* add the free list... */ + if (eat->free_head) + { + unsigned int eat_in_use = eat->alloc_count - eat->free_count; + unsigned int dst_in_use = cache->alloc_count - cache->free_count; + if (!cache->free_head) + cache->free_head = eat->free_head; + else if (eat->total_count - eat_in_use < cache->total_count - dst_ins_use) + { + struct alloccache_free_ent *last = eat->free_head; + while (last->next) + last = last->next; + last->next = cache->free_head; + cache->free_head = eat->free_head; + } + else + { + struct alloccache_free_ent *last = cache->free_head; + while (last->next) + last = last->next; + last->next = eat->free_head; + } + } + + /* ... and the free space. */ + while (eat->free_start != eat->free_end) + { + struct alloccache_free_ent *f = (struct alloccache_free_ent *)eat->free_start; + eat->free_start += eat->size; + f->next = cache->free_head; + cache->free_head = f; + } + + /* and statistics */ + cache->alloc_count += eat->alloc_count; + cache->free_count += eat->free_count; +#else + /* and statistics */ + cache->alloc_count += eat->alloc_count; + cache->free_count += eat->free_count; +#endif + cache->total_count += eat->total_count; + + /* unlink and disable the eat cache */ + if (alloccache_head == eat) + alloccache_head = eat->next; + else + { + struct alloccache *cur = alloccache_head; + while (cur->next != eat) + cur = cur->next; + assert (cur && cur->next == eat); + cur->next = eat->next; + } + + eat->size = 0; + eat->free_end = eat->free_start = NULL; + eat->free_head = NULL; +} + +/* Print one alloc cache. */ +void +alloccache_print (struct alloccache *cache) +{ + printf (_("\n# Alloc Cache: %s\n" + "# Items: size = %-3u total = %-6u"), + cache->name, cache->size, cache->total_count); + MAKE_STATS(printf (_(" in-use = %-6lu"), + cache->alloc_count - cache->free_count);); + MAKE_STATS(printf (_("\n# alloc calls = %-7lu free calls = %-7lu"), + cache->alloc_count, cache->free_count);); + printf ("\n"); +} + +/* Print all alloc caches. */ +void +alloccache_print_all (void) +{ + struct alloccache *cur; + puts (""); + for (cur = alloccache_head; cur; cur = cur->next) + alloccache_print (cur); +} + +#endif /* CONFIG_WITH_ALLOC_CACHES */ + diff --git a/src/kmk/amiga.c b/src/kmk/amiga.c new file mode 100644 index 0000000..cfd0d08 --- /dev/null +++ b/src/kmk/amiga.c @@ -0,0 +1,117 @@ +/* Running commands on Amiga +Copyright (C) 1995-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#include "makeint.h" +#include "variable.h" +#include "amiga.h" +#include +#include +#include +#include +#include + +static const char Amiga_version[] = "$VER: Make 3.74.3 (12.05.96) \n" + "Amiga Port by A. Digulla (digulla@home.lake.de)"; + +int +MyExecute (char **argv) +{ + char * buffer, * ptr; + char ** aptr; + int len = 0; + int status; + + for (aptr=argv; *aptr; aptr++) + { + len += strlen (*aptr) + 4; + } + + buffer = AllocMem (len, MEMF_ANY); + + if (!buffer) + O (fatal, NILF, "MyExecute: Cannot allocate space for calling a command\n"); + + ptr = buffer; + + for (aptr=argv; *aptr; aptr++) + { + if (((*aptr)[0] == ';' && !(*aptr)[1])) + { + *ptr ++ = '"'; + strcpy (ptr, *aptr); + ptr += strlen (ptr); + *ptr ++ = '"'; + } + else if ((*aptr)[0] == '@' && (*aptr)[1] == '@' && !(*aptr)[2]) + { + *ptr ++ = '\n'; + continue; + } + else + { + strcpy (ptr, *aptr); + ptr += strlen (ptr); + } + *ptr ++ = ' '; + *ptr = 0; + } + + ptr[-1] = '\n'; + + status = SystemTags (buffer, + SYS_UserShell, TRUE, + TAG_END); + + FreeMem (buffer, len); + + if (SetSignal (0L,0L) & SIGBREAKF_CTRL_C) + status = 20; + + /* Warnings don't count */ + if (status == 5) + status = 0; + + return status; +} + +char * +wildcard_expansion (char *wc, char *o) +{ +# define PATH_SIZE 1024 + struct AnchorPath * apath; + + if ( (apath = AllocMem (sizeof (struct AnchorPath) + PATH_SIZE, + MEMF_CLEAR)) + ) + { + apath->ap_Strlen = PATH_SIZE; + + if (MatchFirst (wc, apath) == 0) + { + do + { + o = variable_buffer_output (o, apath->ap_Buf, + strlen (apath->ap_Buf)); + o = variable_buffer_output (o, " ",1); + } while (MatchNext (apath) == 0); + } + + MatchEnd (apath); + FreeMem (apath, sizeof (struct AnchorPath) + PATH_SIZE); + } + + return o; +} diff --git a/src/kmk/amiga.h b/src/kmk/amiga.h new file mode 100644 index 0000000..afc910a --- /dev/null +++ b/src/kmk/amiga.h @@ -0,0 +1,18 @@ +/* Definitions for amiga specific things +Copyright (C) 1995-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +int MyExecute (char ** argv); +char * wildcard_expansion (char * wc, char * o); diff --git a/src/kmk/ar.c b/src/kmk/ar.c new file mode 100644 index 0000000..b9c1cf7 --- /dev/null +++ b/src/kmk/ar.c @@ -0,0 +1,328 @@ +/* Interface to 'ar' archives for GNU Make. +Copyright (C) 1988-2016 Free Software Foundation, Inc. + +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#include "makeint.h" + +#ifndef NO_ARCHIVES + +#include "filedef.h" +#include "dep.h" +#include + +/* Return nonzero if NAME is an archive-member reference, zero if not. An + archive-member reference is a name like 'lib(member)' where member is a + non-empty string. + If a name like 'lib((entry))' is used, a fatal error is signaled at + the attempt to use this unsupported feature. */ + +int +ar_name (const char *name) +{ + const char *p = strchr (name, '('); + const char *end; + + if (p == 0 || p == name) + return 0; + + end = p + strlen (p) - 1; + if (*end != ')' || end == p + 1) + return 0; + + if (p[1] == '(' && end[-1] == ')') + OS (fatal, NILF, _("attempt to use unsupported feature: '%s'"), name); + + return 1; +} + + +/* Parse the archive-member reference NAME into the archive and member names. + Creates one allocated string containing both names, pointed to by ARNAME_P. + MEMNAME_P points to the member. */ + +void +ar_parse_name (const char *name, char **arname_p, char **memname_p) +{ + char *p; + + *arname_p = xstrdup (name); + p = strchr (*arname_p, '('); + *(p++) = '\0'; + p[strlen (p) - 1] = '\0'; + *memname_p = p; +} + + +/* This function is called by 'ar_scan' to find which member to look at. */ + +/* ARGSUSED */ +static long int +ar_member_date_1 (int desc UNUSED, const char *mem, int truncated, + long int hdrpos UNUSED, long int datapos UNUSED, + long int size UNUSED, long int date, + int uid UNUSED, int gid UNUSED, unsigned int mode UNUSED, + const void *name) +{ + return ar_name_equal (name, mem, truncated) ? date : 0; +} + +/* Return the modtime of NAME. */ + +time_t +ar_member_date (const char *name) +{ + char *arname; + char *memname; + long int val; + + ar_parse_name (name, &arname, &memname); + + /* Make sure we know the modtime of the archive itself because we are + likely to be called just before commands to remake a member are run, + and they will change the archive itself. + + But we must be careful not to enter_file the archive itself if it does + not exist, because pattern_search assumes that files found in the data + base exist or can be made. */ + { + struct file *arfile; + arfile = lookup_file (arname); + if (arfile == 0 && file_exists_p (arname)) + arfile = enter_file (strcache_add (arname)); + + if (arfile != 0) + (void) f_mtime (arfile, 0); + } + + val = ar_scan (arname, ar_member_date_1, memname); + + free (arname); + + return (val <= 0 ? (time_t) -1 : (time_t) val); +} + +/* Set the archive-member NAME's modtime to now. */ + +#ifdef VMS +int +ar_touch (const char *name) +{ + O (error, NILF, _("touch archive member is not available on VMS")); + return -1; +} +#else +int +ar_touch (const char *name) +{ + char *arname, *memname; + int val; + + ar_parse_name (name, &arname, &memname); + + /* Make sure we know the modtime of the archive itself before we + touch the member, since this will change the archive modtime. */ + { + struct file *arfile; + arfile = enter_file (strcache_add (arname)); + f_mtime (arfile, 0); + } + + val = 1; + switch (ar_member_touch (arname, memname)) + { + case -1: + OS (error, NILF, _("touch: Archive '%s' does not exist"), arname); + break; + case -2: + OS (error, NILF, _("touch: '%s' is not a valid archive"), arname); + break; + case -3: + perror_with_name ("touch: ", arname); + break; + case 1: + OSS (error, NILF, + _("touch: Member '%s' does not exist in '%s'"), memname, arname); + break; + case 0: + val = 0; + break; + default: + OS (error, NILF, + _("touch: Bad return code from ar_member_touch on '%s'"), name); + } + + free (arname); + + return val; +} +#endif /* !VMS */ + +/* State of an 'ar_glob' run, passed to 'ar_glob_match'. */ + +/* On VMS, (object) modules in libraries do not have suffixes. That is, to + find a match for a pattern, the pattern must not have any suffix. So the + suffix of the pattern is saved and the pattern is stripped (ar_glob). + If there is a match and the match, which is a module name, is added to + the chain, the saved suffix is added back to construct a source filename + (ar_glob_match). */ + +struct ar_glob_state + { + const char *arname; + const char *pattern; +#ifdef VMS + char *suffix; +#endif + unsigned int size; + struct nameseq *chain; + unsigned int n; + }; + +/* This function is called by 'ar_scan' to match one archive + element against the pattern in STATE. */ + +static long int +ar_glob_match (int desc UNUSED, const char *mem, int truncated UNUSED, + long int hdrpos UNUSED, long int datapos UNUSED, + long int size UNUSED, long int date UNUSED, int uid UNUSED, + int gid UNUSED, unsigned int mode UNUSED, const void *arg) +{ + struct ar_glob_state *state = (struct ar_glob_state *)arg; + + if (fnmatch (state->pattern, mem, FNM_PATHNAME|FNM_PERIOD) == 0) + { + /* We have a match. Add it to the chain. */ + struct nameseq *new = xcalloc (state->size); +#ifdef VMS + if (state->suffix) + new->name = strcache_add( + concat(5, state->arname, "(", mem, state->suffix, ")")); + else +#endif + new->name = strcache_add(concat(4, state->arname, "(", mem, ")")); + new->next = state->chain; + state->chain = new; + ++state->n; + } + + return 0L; +} + +/* Return nonzero if PATTERN contains any metacharacters. + Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ +static int +ar_glob_pattern_p (const char *pattern, int quote) +{ + const char *p; + int opened = 0; + + for (p = pattern; *p != '\0'; ++p) + switch (*p) + { + case '?': + case '*': + return 1; + + case '\\': + if (quote) + ++p; + break; + + case '[': + opened = 1; + break; + + case ']': + if (opened) + return 1; + break; + } + + return 0; +} + +/* Glob for MEMBER_PATTERN in archive ARNAME. + Return a malloc'd chain of matching elements (or nil if none). */ + +struct nameseq * +ar_glob (const char *arname, const char *member_pattern, unsigned int size) +{ + struct ar_glob_state state; + struct nameseq *n; + const char **names; + unsigned int i; +#ifdef VMS + char *vms_member_pattern; +#endif + if (! ar_glob_pattern_p (member_pattern, 1)) + return 0; + + /* Scan the archive for matches. + ar_glob_match will accumulate them in STATE.chain. */ + state.arname = arname; + state.pattern = member_pattern; +#ifdef VMS + { + /* In a copy of the pattern, find the suffix, save it and remove it from + the pattern */ + char *lastdot; + vms_member_pattern = xstrdup(member_pattern); + lastdot = strrchr(vms_member_pattern, '.'); + state.suffix = lastdot; + if (lastdot) + { + state.suffix = xstrdup(lastdot); + *lastdot = 0; + } + state.pattern = vms_member_pattern; + } +#endif + state.size = size; + state.chain = 0; + state.n = 0; + ar_scan (arname, ar_glob_match, &state); + +#ifdef VMS + /* Deallocate any duplicated string */ + free(vms_member_pattern); + if (state.suffix) + { + free(state.suffix); + } +#endif + + if (state.chain == 0) + return 0; + + /* Now put the names into a vector for sorting. */ + names = alloca (state.n * sizeof (const char *)); + i = 0; + for (n = state.chain; n != 0; n = n->next) + names[i++] = n->name; + + /* Sort them alphabetically. */ + /* MSVC erroneously warns without a cast here. */ + qsort ((void *)names, i, sizeof (*names), alpha_compare); + + /* Put them back into the chain in the sorted order. */ + i = 0; + for (n = state.chain; n != 0; n = n->next) + n->name = names[i++]; + + return state.chain; +} + +#endif /* Not NO_ARCHIVES. */ diff --git a/src/kmk/arscan.c b/src/kmk/arscan.c new file mode 100644 index 0000000..2baa8c8 --- /dev/null +++ b/src/kmk/arscan.c @@ -0,0 +1,982 @@ +/* Library function for scanning an archive file. +Copyright (C) 1987-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#include "makeint.h" + +#ifdef TEST +/* Hack, the real error() routine eventually pulls in die from main.c */ +#define error(a, b, c, d) +#endif + +#ifdef HAVE_FCNTL_H +#include +#else +#include +#endif + +#ifndef NO_ARCHIVES + +#ifdef VMS +#include +#include +#include +#include +#include +#include +#include +#include + +/* This symbol should be present in lbrdef.h. */ +#ifndef LBR$_HDRTRUNC +#pragma extern_model save +#pragma extern_model globalvalue +extern unsigned int LBR$_HDRTRUNC; +#pragma extern_model restore +#endif + +#include +#include + +const char * +vmsify (const char *name, int type); + +/* Time conversion from VMS to Unix + Conversion from local time (stored in library) to GMT (needed for gmake) + Note: The tm_gmtoff element is a VMS extension to the ANSI standard. */ +static time_t +vms_time_to_unix(void *vms_time) +{ + struct tm *tmp; + time_t unix_time; + + unix_time = decc$fix_time(vms_time); + tmp = localtime(&unix_time); + unix_time -= tmp->tm_gmtoff; + + return unix_time; +} + + +/* VMS library routines need static variables for callback */ +static void *VMS_lib_idx; + +static const void *VMS_saved_arg; + +static long int (*VMS_function) (); + +static long int VMS_function_ret; + + +/* This is a callback procedure for lib$get_index */ +static int +VMS_get_member_info(struct dsc$descriptor_s *module, unsigned long *rfa) +{ + int status, i; + const int truncated = 0; /* Member name may be truncated */ + time_t member_date; /* Member date */ + char *filename; + unsigned int buffer_length; /* Actual buffer length */ + + /* Unused constants - Make does not actually use most of these */ + const int file_desc = -1; /* archive file descriptor for reading the data */ + const int header_position = 0; /* Header position */ + const int data_position = 0; /* Data position in file */ + const int data_size = 0; /* Data size */ + const int uid = 0; /* member gid */ + const int gid = 0; /* member gid */ + const int mode = 0; /* member protection mode */ + /* End of unused constants */ + + static struct dsc$descriptor_s bufdesc = + { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL }; + + /* Only need the module definition */ + struct mhddef *mhd; + + /* If a previous callback is non-zero, just return that status */ + if (VMS_function_ret) + { + return SS$_NORMAL; + } + + /* lbr_set_module returns more than just the module header. So allocate + a buffer which is big enough: the maximum LBR$C_MAXHDRSIZ. That's at + least bigger than the size of struct mhddef. + If the request is too small, a buffer truncated warning is issued so + it can be reissued with a larger buffer. + We do not care if the buffer is truncated, so that is still a success. */ + mhd = xmalloc(LBR$C_MAXHDRSIZ); + bufdesc.dsc$a_pointer = (char *) mhd; + bufdesc.dsc$w_length = LBR$C_MAXHDRSIZ; + + status = lbr$set_module(&VMS_lib_idx, rfa, &bufdesc, &buffer_length, 0); + + if ((status != LBR$_HDRTRUNC) && !$VMS_STATUS_SUCCESS(status)) + { + ON(error, NILF, + _("lbr$set_module() failed to extract module info, status = %d"), + status); + + lbr$close(&VMS_lib_idx); + + return status; + } + +#ifdef TEST + /* When testing this code, it is useful to know the length returned */ + printf("Input length = %d, actual = %d\n", + bufdesc.dsc$w_length, buffer_length); +#endif + + /* Conversion from VMS time to C time. + VMS defectlet - mhddef is sub-optimal, for the time, it has a 32 bit + longword, mhd$l_datim, and a 32 bit fill instead of two longwords, or + equivalent. */ + member_date = vms_time_to_unix(&mhd->mhd$l_datim); + free(mhd); + + /* Here we have a problem. The module name on VMS does not have + a file type, but the filename pattern in the "VMS_saved_arg" + may have one. + But only the method being called knows how to interpret the + filename pattern. + There are currently two different formats being used. + This means that we need a VMS specific code in those methods + to handle it. */ + filename = xmalloc(module->dsc$w_length + 1); + + /* TODO: We may need an option to preserve the case of the module + For now force the module name to lower case */ + for (i = 0; i < module->dsc$w_length; i++) + filename[i] = _tolower((unsigned char )module->dsc$a_pointer[i]); + + filename[i] = '\0'; + + VMS_function_ret = (*VMS_function)(file_desc, filename, truncated, + header_position, data_position, data_size, member_date, uid, gid, mode, + VMS_saved_arg); + + free(filename); + return SS$_NORMAL; +} + + +/* Takes three arguments ARCHIVE, FUNCTION and ARG. + + Open the archive named ARCHIVE, find its members one by one, + and for each one call FUNCTION with the following arguments: + archive file descriptor for reading the data, + member name, + member name might be truncated flag, + member header position in file, + member data position in file, + member data size, + member date, + member uid, + member gid, + member protection mode, + ARG. + + NOTE: on VMS systems, only name, date, and arg are meaningful! + + The descriptor is poised to read the data of the member + when FUNCTION is called. It does not matter how much + data FUNCTION reads. + + If FUNCTION returns nonzero, we immediately return + what FUNCTION returned. + + Returns -1 if archive does not exist, + Returns -2 if archive has invalid format. + Returns 0 if have scanned successfully. */ + +long int +ar_scan (const char *archive, ar_member_func_t function, const void *varg) +{ + char *vms_archive; + + static struct dsc$descriptor_s libdesc = + { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL }; + + const unsigned long func = LBR$C_READ; + const unsigned long type = LBR$C_TYP_UNK; + const unsigned long index = 1; + unsigned long lib_idx; + int status; + + VMS_saved_arg = varg; + + /* Null archive string can show up in test and cause an access violation */ + if (archive == NULL) + { + /* Null filenames do not exist */ + return -1; + } + + /* archive path name must be in VMS format */ + vms_archive = (char *) vmsify(archive, 0); + + status = lbr$ini_control(&VMS_lib_idx, &func, &type, 0); + + if (!$VMS_STATUS_SUCCESS(status)) + { + ON(error, NILF, _("lbr$ini_control() failed with status = %d"), status); + return -2; + } + + libdesc.dsc$a_pointer = vms_archive; + libdesc.dsc$w_length = strlen(vms_archive); + + status = lbr$open(&VMS_lib_idx, &libdesc, 0, NULL, 0, NULL, 0); + + if (!$VMS_STATUS_SUCCESS(status)) + { + + /* TODO: A library format failure could mean that this is a file + generated by the GNU AR utility and in that case, we need to + take the UNIX codepath. This will also take a change to the + GNV AR wrapper program. */ + + switch (status) + { + case RMS$_FNF: + /* Archive does not exist */ + return -1; + default: +#ifndef TEST + OSN(error, NILF, + _("unable to open library '%s' to lookup member status %d"), + archive, status); +#endif + /* For library format errors, specification says to return -2 */ + return -2; + } + } + + VMS_function = function; + + /* Clear the return status, as we are supposed to stop calling the + callback function if it becomes non-zero, and this is a static + variable. */ + VMS_function_ret = 0; + + status = lbr$get_index(&VMS_lib_idx, &index, VMS_get_member_info, NULL, 0); + + lbr$close(&VMS_lib_idx); + + /* Unless a failure occurred in the lbr$ routines, return the + the status from the 'function' routine. */ + if ($VMS_STATUS_SUCCESS(status)) + { + return VMS_function_ret; + } + + /* This must be something wrong with the library and an error + message should already have been printed. */ + return -2; +} + +#else /* !VMS */ + +/* SCO Unix's compiler defines both of these. */ +#ifdef M_UNIX +#undef M_XENIX +#endif + +/* On the sun386i and in System V rel 3, ar.h defines two different archive + formats depending upon whether you have defined PORTAR (normal) or PORT5AR + (System V Release 1). There is no default, one or the other must be defined + to have a nonzero value. */ + +#if (!defined (PORTAR) || PORTAR == 0) && (!defined (PORT5AR) || PORT5AR == 0) +#undef PORTAR +#ifdef M_XENIX +/* According to Jim Sievert , for SCO XENIX defining + PORTAR to 1 gets the wrong archive format, and defining it to 0 gets the + right one. */ +#define PORTAR 0 +#else +#define PORTAR 1 +#endif +#endif + +/* On AIX, define these symbols to be sure to get both archive formats. + AIX 4.3 introduced the "big" archive format to support 64-bit object + files, so on AIX 4.3 systems we need to support both the "normal" and + "big" archive formats. An archive's format is indicated in the + "fl_magic" field of the "FL_HDR" structure. For a normal archive, + this field will be the string defined by the AIAMAG symbol. For a + "big" archive, it will be the string defined by the AIAMAGBIG symbol + (at least on AIX it works this way). + + Note: we'll define these symbols regardless of which AIX version + we're compiling on, but this is okay since we'll use the new symbols + only if they're present. */ +#ifdef _AIX +# define __AR_SMALL__ +# define __AR_BIG__ +#endif + +#ifndef WINDOWS32 +# if !defined (__ANDROID__) && !defined (__BEOS__) && !defined (__HAIKU__) /* bird: exclude haiku */ +# include +# else + /* These platforms don't have but have archives in the same format + * as many other Unices. This was taken from GNU binutils for BeOS. + */ +# define ARMAG "!\n" /* String that begins an archive file. */ +# define SARMAG 8 /* Size of that string. */ +# define ARFMAG "`\n" /* String in ar_fmag at end of each header. */ +struct ar_hdr + { + char ar_name[16]; /* Member file name, sometimes / terminated. */ + char ar_date[12]; /* File date, decimal seconds since Epoch. */ + char ar_uid[6], ar_gid[6]; /* User and group IDs, in ASCII decimal. */ + char ar_mode[8]; /* File mode, in ASCII octal. */ + char ar_size[10]; /* File size, in ASCII decimal. */ + char ar_fmag[2]; /* Always contains ARFMAG. */ + }; +# endif +# define TOCHAR(_m) (_m) +#else +/* These should allow us to read Windows (VC++) libraries (according to Frank + * Libbrecht ) + */ +# include +# include +# include +# define ARMAG IMAGE_ARCHIVE_START +# define SARMAG IMAGE_ARCHIVE_START_SIZE +# define ar_hdr _IMAGE_ARCHIVE_MEMBER_HEADER +# define ar_name Name +# define ar_mode Mode +# define ar_size Size +# define ar_date Date +# define ar_uid UserID +# define ar_gid GroupID +/* In Windows the member names have type BYTE so we must cast them. */ +# define TOCHAR(_m) ((char *)(_m)) +#endif + +/* Cray's apparently defines this. */ +#ifndef AR_HDR_SIZE +# define AR_HDR_SIZE (sizeof (struct ar_hdr)) +#endif + +/* Takes three arguments ARCHIVE, FUNCTION and ARG. + + Open the archive named ARCHIVE, find its members one by one, + and for each one call FUNCTION with the following arguments: + archive file descriptor for reading the data, + member name, + member name might be truncated flag, + member header position in file, + member data position in file, + member data size, + member date, + member uid, + member gid, + member protection mode, + ARG. + + The descriptor is poised to read the data of the member + when FUNCTION is called. It does not matter how much + data FUNCTION reads. + + If FUNCTION returns nonzero, we immediately return + what FUNCTION returned. + + Returns -1 if archive does not exist, + Returns -2 if archive has invalid format. + Returns 0 if have scanned successfully. */ + +long int +ar_scan (const char *archive, ar_member_func_t function, const void *arg) +{ +#ifdef AIAMAG + FL_HDR fl_header; +# ifdef AIAMAGBIG + int big_archive = 0; + FL_HDR_BIG fl_header_big; +# endif +#endif + char *namemap = 0; + int desc = open (archive, O_RDONLY, 0); + if (desc < 0) + return -1; +#ifdef SARMAG + { + char buf[SARMAG]; + int nread; + EINTRLOOP (nread, read (desc, buf, SARMAG)); + if (nread != SARMAG || memcmp (buf, ARMAG, SARMAG)) + { + (void) close (desc); + return -2; + } + } +#else +#ifdef AIAMAG + { + int nread; + EINTRLOOP (nread, read (desc, &fl_header, FL_HSZ)); + if (nread != FL_HSZ) + { + (void) close (desc); + return -2; + } +#ifdef AIAMAGBIG + /* If this is a "big" archive, then set the flag and + re-read the header into the "big" structure. */ + if (!memcmp (fl_header.fl_magic, AIAMAGBIG, SAIAMAG)) + { + off_t o; + + big_archive = 1; + + /* seek back to beginning of archive */ + EINTRLOOP (o, lseek (desc, 0, 0)); + if (o < 0) + { + (void) close (desc); + return -2; + } + + /* re-read the header into the "big" structure */ + EINTRLOOP (nread, read (desc, &fl_header_big, FL_HSZ_BIG)); + if (nread != FL_HSZ_BIG) + { + (void) close (desc); + return -2; + } + } + else +#endif + /* Check to make sure this is a "normal" archive. */ + if (memcmp (fl_header.fl_magic, AIAMAG, SAIAMAG)) + { + (void) close (desc); + return -2; + } + } +#else + { +#ifndef M_XENIX + int buf; +#else + unsigned short int buf; +#endif + int nread; + EINTRLOOP (nread, read (desc, &buf, sizeof (buf))); + if (nread != sizeof (buf) || buf != ARMAG) + { + (void) close (desc); + return -2; + } + } +#endif +#endif + + /* Now find the members one by one. */ + { +#ifdef SARMAG + register long int member_offset = SARMAG; +#else +#ifdef AIAMAG + long int member_offset; + long int last_member_offset; + +#ifdef AIAMAGBIG + if ( big_archive ) + { + sscanf (fl_header_big.fl_fstmoff, "%20ld", &member_offset); + sscanf (fl_header_big.fl_lstmoff, "%20ld", &last_member_offset); + } + else +#endif + { + sscanf (fl_header.fl_fstmoff, "%12ld", &member_offset); + sscanf (fl_header.fl_lstmoff, "%12ld", &last_member_offset); + } + + if (member_offset == 0) + { + /* Empty archive. */ + close (desc); + return 0; + } +#else +#ifndef M_XENIX + register long int member_offset = sizeof (int); +#else /* Xenix. */ + register long int member_offset = sizeof (unsigned short int); +#endif /* Not Xenix. */ +#endif +#endif + + while (1) + { + register int nread; + struct ar_hdr member_header; +#ifdef AIAMAGBIG + struct ar_hdr_big member_header_big; +#endif +#ifdef AIAMAG + char name[256]; + int name_len; + long int dateval; + int uidval, gidval; + long int data_offset; +#else + char namebuf[sizeof member_header.ar_name + 1]; + char *name; + int is_namemap; /* Nonzero if this entry maps long names. */ + int long_name = 0; +#endif + long int eltsize; + unsigned int eltmode; + long int fnval; + off_t o; + + EINTRLOOP (o, lseek (desc, member_offset, 0)); + if (o < 0) + { + (void) close (desc); + return -2; + } + +#ifdef AIAMAG +#define AR_MEMHDR_SZ(x) (sizeof(x) - sizeof (x._ar_name)) + +#ifdef AIAMAGBIG + if (big_archive) + { + EINTRLOOP (nread, read (desc, &member_header_big, + AR_MEMHDR_SZ(member_header_big))); + + if (nread != AR_MEMHDR_SZ(member_header_big)) + { + (void) close (desc); + return -2; + } + + sscanf (member_header_big.ar_namlen, "%4d", &name_len); + EINTRLOOP (nread, read (desc, name, name_len)); + + if (nread != name_len) + { + (void) close (desc); + return -2; + } + + name[name_len] = 0; + + sscanf (member_header_big.ar_date, "%12ld", &dateval); + sscanf (member_header_big.ar_uid, "%12d", &uidval); + sscanf (member_header_big.ar_gid, "%12d", &gidval); + sscanf (member_header_big.ar_mode, "%12o", &eltmode); + sscanf (member_header_big.ar_size, "%20ld", &eltsize); + + data_offset = (member_offset + AR_MEMHDR_SZ(member_header_big) + + name_len + 2); + } + else +#endif + { + EINTRLOOP (nread, read (desc, &member_header, + AR_MEMHDR_SZ(member_header))); + + if (nread != AR_MEMHDR_SZ(member_header)) + { + (void) close (desc); + return -2; + } + + sscanf (member_header.ar_namlen, "%4d", &name_len); + EINTRLOOP (nread, read (desc, name, name_len)); + + if (nread != name_len) + { + (void) close (desc); + return -2; + } + + name[name_len] = 0; + + sscanf (member_header.ar_date, "%12ld", &dateval); + sscanf (member_header.ar_uid, "%12d", &uidval); + sscanf (member_header.ar_gid, "%12d", &gidval); + sscanf (member_header.ar_mode, "%12o", &eltmode); + sscanf (member_header.ar_size, "%12ld", &eltsize); + + data_offset = (member_offset + AR_MEMHDR_SZ(member_header) + + name_len + 2); + } + data_offset += data_offset % 2; + + fnval = + (*function) (desc, name, 0, + member_offset, data_offset, eltsize, + dateval, uidval, gidval, + eltmode, arg); + +#else /* Not AIAMAG. */ + EINTRLOOP (nread, read (desc, &member_header, AR_HDR_SIZE)); + if (nread == 0) + /* No data left means end of file; that is OK. */ + break; + + if (nread != AR_HDR_SIZE +#if defined(ARFMAG) || defined(ARFZMAG) + || ( +# ifdef ARFMAG + memcmp (member_header.ar_fmag, ARFMAG, 2) +# else + 1 +# endif + && +# ifdef ARFZMAG + memcmp (member_header.ar_fmag, ARFZMAG, 2) +# else + 1 +# endif + ) +#endif + ) + { + (void) close (desc); + return -2; + } + + name = namebuf; + memcpy (name, member_header.ar_name, sizeof member_header.ar_name); + { + register char *p = name + sizeof member_header.ar_name; + do + *p = '\0'; + while (p > name && *--p == ' '); + +#ifndef AIAMAG + /* If the member name is "//" or "ARFILENAMES/" this may be + a list of file name mappings. The maximum file name + length supported by the standard archive format is 14 + characters. This member will actually always be the + first or second entry in the archive, but we don't check + that. */ + is_namemap = (!strcmp (name, "//") + || !strcmp (name, "ARFILENAMES/")); +#endif /* Not AIAMAG. */ + /* On some systems, there is a slash after each member name. */ + if (*p == '/') + *p = '\0'; + +#ifndef AIAMAG + /* If the member name starts with a space or a slash, this + is an index into the file name mappings (used by GNU ar). + Otherwise if the member name looks like #1/NUMBER the + real member name appears in the element data (used by + 4.4BSD). */ + if (! is_namemap + && (name[0] == ' ' || name[0] == '/') + && namemap != 0) + { + name = namemap + atoi (name + 1); + long_name = 1; + } + else if (name[0] == '#' + && name[1] == '1' + && name[2] == '/') + { + int namesize = atoi (name + 3); + + name = alloca (namesize + 1); + EINTRLOOP (nread, read (desc, name, namesize)); + if (nread != namesize) + { + close (desc); + return -2; + } + name[namesize] = '\0'; + + long_name = 1; + } +#endif /* Not AIAMAG. */ + } + +#ifndef M_XENIX + sscanf (TOCHAR (member_header.ar_mode), "%o", &eltmode); + eltsize = atol (TOCHAR (member_header.ar_size)); +#else /* Xenix. */ + eltmode = (unsigned short int) member_header.ar_mode; + eltsize = member_header.ar_size; +#endif /* Not Xenix. */ + + fnval = + (*function) (desc, name, ! long_name, member_offset, + member_offset + AR_HDR_SIZE, eltsize, +#ifndef M_XENIX + atol (TOCHAR (member_header.ar_date)), + atoi (TOCHAR (member_header.ar_uid)), + atoi (TOCHAR (member_header.ar_gid)), +#else /* Xenix. */ + member_header.ar_date, + member_header.ar_uid, + member_header.ar_gid, +#endif /* Not Xenix. */ + eltmode, arg); + +#endif /* AIAMAG. */ + + if (fnval) + { + (void) close (desc); + return fnval; + } + +#ifdef AIAMAG + if (member_offset == last_member_offset) + /* End of the chain. */ + break; + +#ifdef AIAMAGBIG + if (big_archive) + sscanf (member_header_big.ar_nxtmem, "%20ld", &member_offset); + else +#endif + sscanf (member_header.ar_nxtmem, "%12ld", &member_offset); + + if (lseek (desc, member_offset, 0) != member_offset) + { + (void) close (desc); + return -2; + } +#else + + /* If this member maps archive names, we must read it in. The + name map will always precede any members whose names must + be mapped. */ + if (is_namemap) + { + char *clear; + char *limit; + + namemap = alloca (eltsize); + EINTRLOOP (nread, read (desc, namemap, eltsize)); + if (nread != eltsize) + { + (void) close (desc); + return -2; + } + + /* The names are separated by newlines. Some formats have + a trailing slash. Null terminate the strings for + convenience. */ + limit = namemap + eltsize; + for (clear = namemap; clear < limit; clear++) + { + if (*clear == '\n') + { + *clear = '\0'; + if (clear[-1] == '/') + clear[-1] = '\0'; + } + } + + is_namemap = 0; + } + + member_offset += AR_HDR_SIZE + eltsize; + if (member_offset % 2 != 0) + member_offset++; +#endif + } + } + + close (desc); + return 0; +} +#endif /* !VMS */ + +/* Return nonzero iff NAME matches MEM. + If TRUNCATED is nonzero, MEM may be truncated to + sizeof (struct ar_hdr.ar_name) - 1. */ + +int +ar_name_equal (const char *name, const char *mem, int truncated) +{ + const char *p; + + p = strrchr (name, '/'); + if (p != 0) + name = p + 1; + +#ifndef VMS + if (truncated) + { +#ifdef AIAMAG + /* TRUNCATED should never be set on this system. */ + abort (); +#else + struct ar_hdr hdr; +#if !defined (__hpux) && !defined (cray) + return strneq (name, mem, sizeof (hdr.ar_name) - 1); +#else + return strneq (name, mem, sizeof (hdr.ar_name) - 2); +#endif /* !__hpux && !cray */ +#endif /* !AIAMAG */ + } + + return !strcmp (name, mem); +#else + /* VMS members do not have suffixes, but the filenames usually + have. + Do we need to strip VMS disk/directory format paths? + + Most VMS compilers etc. by default are case insensitive + but produce uppercase external names, incl. module names. + However the VMS librarian (ar) and the linker by default + are case sensitive: they take what they get, usually + uppercase names. So for the non-default settings of the + compilers etc. there is a need to have a case sensitive + mode. */ + { + int len; + len = strlen(mem); + int match; + char *dot; + if ((dot=strrchr(name,'.'))) + match = (len == dot - name) && !strncasecmp(name, mem, len); + else + match = !strcasecmp (name, mem); + return match; + } +#endif /* !VMS */ +} + +#ifndef VMS +/* ARGSUSED */ +static long int +ar_member_pos (int desc UNUSED, const char *mem, int truncated, + long int hdrpos, long int datapos UNUSED, long int size UNUSED, + long int date UNUSED, int uid UNUSED, int gid UNUSED, + unsigned int mode UNUSED, const void *name) +{ + if (!ar_name_equal (name, mem, truncated)) + return 0; + return hdrpos; +} + +/* Set date of member MEMNAME in archive ARNAME to current time. + Returns 0 if successful, + -1 if file ARNAME does not exist, + -2 if not a valid archive, + -3 if other random system call error (including file read-only), + 1 if valid but member MEMNAME does not exist. */ + +int +ar_member_touch (const char *arname, const char *memname) +{ + long int pos = ar_scan (arname, ar_member_pos, memname); + int fd; + struct ar_hdr ar_hdr; + off_t o; + int r; + unsigned int ui; + struct stat statbuf; + + if (pos < 0) + return (int) pos; + if (!pos) + return 1; + + EINTRLOOP (fd, open (arname, O_RDWR, 0666)); + if (fd < 0) + return -3; + /* Read in this member's header */ + EINTRLOOP (o, lseek (fd, pos, 0)); + if (o < 0) + goto lose; + EINTRLOOP (r, read (fd, &ar_hdr, AR_HDR_SIZE)); + if (r != AR_HDR_SIZE) + goto lose; + /* Write back the header, thus touching the archive file. */ + EINTRLOOP (o, lseek (fd, pos, 0)); + if (o < 0) + goto lose; + EINTRLOOP (r, write (fd, &ar_hdr, AR_HDR_SIZE)); + if (r != AR_HDR_SIZE) + goto lose; + /* The file's mtime is the time we we want. */ + EINTRLOOP (r, fstat (fd, &statbuf)); + if (r < 0) + goto lose; +#if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32) + /* Advance member's time to that time */ + for (ui = 0; ui < sizeof ar_hdr.ar_date; ui++) + ar_hdr.ar_date[ui] = ' '; + sprintf (TOCHAR (ar_hdr.ar_date), "%lu", (long unsigned) statbuf.st_mtime); +#ifdef AIAMAG + ar_hdr.ar_date[strlen (ar_hdr.ar_date)] = ' '; +#endif +#else + ar_hdr.ar_date = statbuf.st_mtime; +#endif + /* Write back this member's header */ + EINTRLOOP (o, lseek (fd, pos, 0)); + if (o < 0) + goto lose; + EINTRLOOP (r, write (fd, &ar_hdr, AR_HDR_SIZE)); + if (r != AR_HDR_SIZE) + goto lose; + close (fd); + return 0; + + lose: + r = errno; + close (fd); + errno = r; + return -3; +} +#endif + +#ifdef TEST + +long int +describe_member (int desc, const char *name, int truncated, + long int hdrpos, long int datapos, long int size, + long int date, int uid, int gid, unsigned int mode, + const void *arg) +{ + extern char *ctime (); + + printf (_("Member '%s'%s: %ld bytes at %ld (%ld).\n"), + name, truncated ? _(" (name might be truncated)") : "", + size, hdrpos, datapos); + printf (_(" Date %s"), ctime (&date)); + printf (_(" uid = %d, gid = %d, mode = 0%o.\n"), uid, gid, mode); + + return 0; +} + +int +main (int argc, char **argv) +{ + ar_scan (argv[1], describe_member, NULL); + return 0; +} + +#endif /* TEST. */ +#endif /* NO_ARCHIVES. */ diff --git a/src/kmk/build.template b/src/kmk/build.template new file mode 100644 index 0000000..4b01b46 --- /dev/null +++ b/src/kmk/build.template @@ -0,0 +1,81 @@ +#!/bin/sh +# Shell script to build GNU Make in the absence of any 'make' program. +# @configure_input@ + +# Copyright (C) 1993-2016 Free Software Foundation, Inc. +# This file is part of GNU Make. +# +# GNU Make is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +# See Makefile.in for comments describing these variables. + +srcdir='@srcdir@' +CC='@CC@' +CFLAGS='@CFLAGS@ @GUILE_CFLAGS@' +CPPFLAGS='@CPPFLAGS@' +LDFLAGS='@AM_LDFLAGS@ @LDFLAGS@' +ALLOCA='@ALLOCA@' +LOADLIBES='@LIBS@ @GUILE_LIBS@ @LIBINTL@' +eval extras=\'@LIBOBJS@\' +REMOTE='@REMOTE@' +GLOBLIB='@GLOBLIB@' +PATH_SEPARATOR='@PATH_SEPARATOR@' +OBJEXT='@OBJEXT@' +EXEEXT='@EXEEXT@' + +# Common prefix for machine-independent installed files. +prefix='@prefix@' +# Common prefix for machine-dependent installed files. +exec_prefix=`eval echo @exec_prefix@` +# Directory to find libraries in for '-lXXX'. +libdir=${exec_prefix}/lib +# Directory to search by default for included makefiles. +includedir=${prefix}/include + +localedir=${prefix}/share/locale +aliaspath=${localedir}${PATH_SEPARATOR}. + +defines="-DLOCALEDIR=\"${localedir}\" -DLIBDIR=\"${libdir}\" -DINCLUDEDIR=\"${includedir}\""' @DEFS@' + +# Exit as soon as any command fails. +set -e + +# These are all the objects we need to link together. +objs="%objs% remote-${REMOTE}.${OBJEXT} ${extras} ${ALLOCA}" + +if [ x"$GLOBLIB" != x ]; then + objs="$objs %globobjs%" + globinc=-I${srcdir}/glob +fi + +# Compile the source files into those objects. +for file in `echo ${objs} | sed 's/\.'${OBJEXT}'/.c/g'`; do + echo compiling ${file}... + $CC $defines $CPPFLAGS $CFLAGS \ + -c -I. -I${srcdir} ${globinc} ${srcdir}/$file +done + +# The object files were actually all put in the current directory. +# Remove the source directory names from the list. +srcobjs="$objs" +objs= +for obj in $srcobjs; do + objs="$objs `basename $obj`" +done + +# Link all the objects together. +echo linking make... +$CC $CFLAGS $LDFLAGS $objs $LOADLIBES -o makenew${EXEEXT} +echo done +mv -f makenew${EXEEXT} make${EXEEXT} diff --git a/src/kmk/build_w32.bat b/src/kmk/build_w32.bat new file mode 100644 index 0000000..59e068b --- /dev/null +++ b/src/kmk/build_w32.bat @@ -0,0 +1,250 @@ +@echo off +rem Copyright (C) 1996-2016 Free Software Foundation, Inc. +rem This file is part of GNU Make. +rem +rem GNU Make is free software; you can redistribute it and/or modify it under +rem the terms of the GNU General Public License as published by the Free +rem Software Foundation; either version 3 of the License, or (at your option) +rem any later version. +rem +rem GNU Make is distributed in the hope that it will be useful, but WITHOUT +rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for. +rem more details. +rem +rem You should have received a copy of the GNU General Public License along +rem with this program. If not, see . + +call :Reset + +if "%1" == "-h" goto Usage +if "%1" == "--help" goto Usage + +set MAKE=gnumake +set GUILE=Y +set COMPILER=msvc + +:ParseSW +if "%1" == "--debug" goto SetDebug +if "%1" == "--without-guile" goto NoGuile +if "%1" == "gcc" goto SetCC +if "%1" == "" goto DoneSW + +:SetDebug +set DEBUG=Y +shift +goto ParseSW + +:NoGuile +set GUILE=N +echo Building without Guile +shift +goto ParseSW + +:SetCC +set COMPILER=gcc +echo Building with GCC +shift +goto ParseSW + +rem Build with Guile is supported only on NT and later versions +:DoneSW +echo. +echo Creating GNU Make for Windows 9X/NT/2K/XP/Vista/7/8 +if "%DEBUG%" == "Y" echo Building without compiler optimizations + +if "%COMPILER%" == "gcc" goto GccBuild + +set OUTDIR=.\WinRel +set "OPTS=/O2 /D NDEBUG" +set LINKOPTS= +if "%DEBUG%" == "Y" set OUTDIR=.\WinDebug +if "%DEBUG%" == "Y" set "OPTS=/Zi /Od /D _DEBUG" +if "%DEBUG%" == "Y" set LINKOPTS=/DEBUG +call :Build +goto Done + +:GccBuild +set OUTDIR=.\GccRel +set OPTS=-O2 +if "%DEBUG%" == "Y" set OPTS=-O0 +if "%DEBUG%" == "Y" set OUTDIR=.\GccDebug +call :Build +goto Done + +:Done +call :Reset +goto :EOF + +:Build +:: Clean the directory if it exists +if exist %OUTDIR%\nul rmdir /S /Q %OUTDIR% + +:: Recreate it +mkdir %OUTDIR% +mkdir %OUTDIR%\glob +mkdir %OUTDIR%\w32 +mkdir %OUTDIR%\w32\compat +mkdir %OUTDIR%\w32\subproc + +if "%GUILE%" == "Y" call :ChkGuile + +echo. +echo Compiling %OUTDIR% version + +if exist config.h.W32.template call :ConfigSCM +copy config.h.W32 %OUTDIR%\config.h + +call :Compile ar +call :Compile arscan +call :Compile commands +call :Compile default +call :Compile dir +call :Compile expand +call :Compile file +call :Compile function +call :Compile getloadavg +call :Compile getopt +call :Compile getopt1 +call :Compile glob\fnmatch +call :Compile glob\glob +call :Compile guile GUILE +call :Compile hash +call :Compile implicit +call :Compile job +call :Compile load +call :Compile loadapi +call :Compile main GUILE +call :Compile misc +call :Compile output +call :Compile read +call :Compile remake +call :Compile remote-stub +call :Compile rule +call :Compile signame +call :Compile strcache +call :Compile variable +call :Compile version +call :Compile vpath +call :Compile w32\compat\posixfcn +call :Compile w32\pathstuff +call :Compile w32\subproc\misc +call :Compile w32\subproc\sub_proc +call :Compile w32\subproc\w32err +call :Compile w32\w32os + +if not "%COMPILER%" == "gcc" call :Compile w32\compat\dirent + +call :Link + +echo. +if not exist %OUTDIR%\%MAKE%.exe echo %OUTDIR% build FAILED! +if exist %OUTDIR%\%MAKE%.exe echo %OUTDIR% build succeeded. +goto :EOF + +:Compile +set EXTRAS= +if "%2" == "GUILE" set "EXTRAS=%GUILECFLAGS%" +if "%COMPILER%" == "gcc" goto GccCompile + +:: MSVC Compile +echo on +cl.exe /nologo /MT /W4 /EHsc %OPTS% /I %OUTDIR% /I . /I glob /I w32/include /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR%OUTDIR% /Fp%OUTDIR%\%MAKE%.pch /Fo%OUTDIR%\%1.obj /Fd%OUTDIR%\%MAKE%.pdb %EXTRAS% /c %1.c +@echo off +echo %OUTDIR%\%1.obj >>%OUTDIR%\link.sc +goto :EOF + +:GccCompile +:: GCC Compile +echo on +gcc -mthreads -Wall -std=gnu99 -gdwarf-2 -g3 %OPTS% -I%OUTDIR% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H %EXTRAS% -o %OUTDIR%\%1.o -c %1.c +@echo off +goto :EOF + +:Link +echo Linking %OUTDIR%/%MAKE%.exe +if "%COMPILER%" == "gcc" goto GccLink + +:: MSVC Link +echo %GUILELIBS% kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib >>%OUTDIR%\link.sc +echo on +link.exe /NOLOGO /SUBSYSTEM:console /PDB:%OUTDIR%\%MAKE%.pdb %LINKOPTS% /OUT:%OUTDIR%\%MAKE%.exe @%OUTDIR%\link.sc +@echo off +goto :EOF + +:GccLink +:: GCC Link +echo on +gcc -mthreads -gdwarf-2 -g3 -o %OUTDIR%\%MAKE%.exe %OUTDIR%\variable.o %OUTDIR%\rule.o %OUTDIR%\remote-stub.o %OUTDIR%\commands.o %OUTDIR%\file.o %OUTDIR%\getloadavg.o %OUTDIR%\default.o %OUTDIR%\signame.o %OUTDIR%\expand.o %OUTDIR%\dir.o %OUTDIR%\main.o %OUTDIR%\getopt1.o %OUTDIR%\guile.o %OUTDIR%\job.o %OUTDIR%\output.o %OUTDIR%\read.o %OUTDIR%\version.o %OUTDIR%\getopt.o %OUTDIR%\arscan.o %OUTDIR%\remake.o %OUTDIR%\misc.o %OUTDIR%\hash.o %OUTDIR%\strcache.o %OUTDIR%\ar.o %OUTDIR%\function.o %OUTDIR%\vpath.o %OUTDIR%\implicit.o %OUTDIR%\loadapi.o %OUTDIR%\load.o %OUTDIR%\glob\glob.o %OUTDIR%\glob\fnmatch.o %OUTDIR%\w32\pathstuff.o %OUTDIR%\w32\compat\posixfcn.o %OUTDIR%\w32\w32os.o %OUTDIR%\w32\subproc\misc.o %OUTDIR%\w32\subproc\sub_proc.o %OUTDIR%\w32\subproc\w32err.o %GUILELIBS% -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -Wl,--out-implib=%OUTDIR%\libgnumake-1.dll.a +@echo off +goto :EOF + +:ConfigSCM +echo Generating config from SCM templates +sed -n "s/^AC_INIT(\[GNU make\],\[\([^]]\+\)\].*/s,%%VERSION%%,\1,g/p" configure.ac > %OUTDIR%\config.h.W32.sed +echo s,%%PACKAGE%%,make,g >> %OUTDIR%\config.h.W32.sed +sed -f %OUTDIR%\config.h.W32.sed config.h.W32.template > config.h.W32 +echo static const char *const GUILE_module_defn = ^" \> gmk-default.h +sed -e "s/;.*//" -e "/^[ \t]*$/d" -e "s/\"/\\\\\"/g" -e "s/$/ \\\/" gmk-default.scm >> gmk-default.h +echo ^";>> gmk-default.h +goto :EOF + +:ChkGuile +if not "%OS%" == "Windows_NT" goto NoGuile +pkg-config --help > %OUTDIR%\guile.tmp 2> NUL +if ERRORLEVEL 1 goto NoPkgCfg + +echo Checking for Guile 2.0 +if not "%COMPILER%" == "gcc" set PKGMSC=--msvc-syntax +pkg-config --cflags --short-errors "guile-2.0" > %OUTDIR%\guile.tmp +if not ERRORLEVEL 1 set /P GUILECFLAGS= < %OUTDIR%\guile.tmp + +pkg-config --libs --static --short-errors %PKGMSC% "guile-2.0" > %OUTDIR%\guile.tmp +if not ERRORLEVEL 1 set /P GUILELIBS= < %OUTDIR%\guile.tmp + +if not "%GUILECFLAGS%" == "" goto GuileDone + +echo Checking for Guile 1.8 +pkg-config --cflags --short-errors "guile-1.8" > %OUTDIR%\guile.tmp +if not ERRORLEVEL 1 set /P GUILECFLAGS= < %OUTDIR%\guile.tmp + +pkg-config --libs --static --short-errors %PKGMSC% "guile-1.8" > %OUTDIR%\guile.tmp +if not ERRORLEVEL 1 set /P GUILELIBS= < %OUTDIR%\guile.tmp + +if not "%GUILECFLAGS%" == "" goto GuileDone + +echo No Guile found, building without Guile +goto GuileDone + +:NoPkgCfg +echo pkg-config not found, building without Guile + +:GuileDone +if "%GUILECFLAGS%" == "" goto :EOF + +echo Guile found, building with Guile +set "GUILECFLAGS=%GUILECFLAGS% -DHAVE_GUILE" +goto :EOF + +:Usage +echo Usage: %0 [options] [gcc] +echo Options: +echo. --debug For GCC only, make a debug build +echo. (MSVC build always makes both debug and release) +echo. --without-guile Do not compile Guile support even if found +echo. --help Display these instructions and exit +goto :EOF + +:Reset +set COMPILER= +set DEBUG= +set GUILE= +set GUILECFLAGS= +set GUILELIBS= +set LINKOPTS= +set MAKE= +set NOGUILE= +set OPTS= +set OUTDIR= +set PKGMSC= +goto :EOF diff --git a/src/kmk/commands.c b/src/kmk/commands.c new file mode 100644 index 0000000..619839c --- /dev/null +++ b/src/kmk/commands.c @@ -0,0 +1,954 @@ +/* Command processing for GNU Make. +Copyright (C) 1988-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#include "makeint.h" +#include "filedef.h" +#include "dep.h" +#include "variable.h" +#include "job.h" +#include "commands.h" +#ifdef WINDOWS32 +#include +#include "w32err.h" +# ifdef CONFIG_NEW_WIN_CHILDREN +# include "w32/winchildren.h" +# endif +#endif +#ifdef CONFIG_WITH_LAZY_DEPS_VARS +# include +#endif + +#if VMS +# define FILE_LIST_SEPARATOR (vms_comma_separator ? ',' : ' ') +#else +# define FILE_LIST_SEPARATOR ' ' +#endif + +#ifndef HAVE_UNISTD_H +int getpid (); +#endif + +#ifndef CONFIG_WITH_STRCACHE2 + +static unsigned long +dep_hash_1 (const void *key) +{ + const struct dep *d = key; + return_STRING_HASH_1 (dep_name (d)); +} + +static unsigned long +dep_hash_2 (const void *key) +{ + const struct dep *d = key; + return_STRING_HASH_2 (dep_name (d)); +} + +static int +dep_hash_cmp (const void *x, const void *y) +{ + const struct dep *dx = x; + const struct dep *dy = y; + return strcmp (dep_name (dx), dep_name (dy)); +} + + +#else /* CONFIG_WITH_STRCACHE2 */ + +/* Exploit the fact that all names are in the string cache. This means equal + names shall have the same storage and there is no need for hashing or + comparing. Use the address as the first hash, avoiding any touching of + the name, and the length as the second. */ + +static unsigned long +dep_hash_1 (const void *key) +{ + const char *name = dep_name ((struct dep const *) key); + assert (strcache2_is_cached (&file_strcache, name)); + return (size_t) name / sizeof(void *); +} + +static unsigned long +dep_hash_2 (const void *key) +{ + const char *name = dep_name ((struct dep const *) key); + return strcache2_get_len (&file_strcache, name); +} + +static int +dep_hash_cmp (const void *x, const void *y) +{ + struct dep *dx = (struct dep *) x; + struct dep *dy = (struct dep *) y; + const char *dxname = dep_name (dx); + const char *dyname = dep_name (dy); + int cmp = dxname == dyname ? 0 : 1; + + /* check preconds: both cached and the cache contains no duplicates. */ + assert (strcache2_is_cached (&file_strcache, dxname)); + assert (strcache2_is_cached (&file_strcache, dyname)); + assert (cmp == 0 || strcmp (dxname, dyname) != 0); + + /* If the names are the same but ignore_mtimes are not equal, one of these + is an order-only prerequisite and one isn't. That means that we should + remove the one that isn't and keep the one that is. */ + + if (!cmp && dx->ignore_mtime != dy->ignore_mtime) + dx->ignore_mtime = dy->ignore_mtime = 0; + + return cmp; +} + +#endif /* CONFIG_WITH_STRCACHE2 */ + +#ifdef CONFIG_WITH_LAZY_DEPS_VARS +/* Create as copy of DEPS without duplicates, similar to what + set_file_variables does. Used by func_deps. */ + +struct dep *create_uniqute_deps_chain (struct dep *deps) +{ + struct dep *d; + struct dep *head = NULL; + struct dep **ppnext= &head; + struct hash_table dep_hash; + void **slot; + + hash_init (&dep_hash, 500, dep_hash_1, dep_hash_2, dep_hash_cmp); + + for (d = deps; d != 0; d = d->next) + { + if (d->need_2nd_expansion) + continue; + + slot = hash_find_slot (&dep_hash, d); + if (HASH_VACANT (*slot)) + { + struct dep *n = alloc_dep(); + *n = *d; + n->next = NULL; + *ppnext = n; + ppnext = &n->next; + hash_insert_at (&dep_hash, n, slot); + } + else + { + /* Upgrade order only if a normal dep exists. + Note! Elected not to upgrade the original, only the sanitized + list, need to check that out later. FIXME TODO */ + struct dep *d2 = (struct dep *)*slot; + if (d->ignore_mtime != d2->ignore_mtime) + d->ignore_mtime = d2->ignore_mtime = 0; + } + } + + return head; +} +#endif /* CONFIG_WITH_LAZY_DEPS_VARS */ + +/* Set FILE's automatic variables up. */ + +void +#if defined(CONFIG_WITH_COMMANDS_FUNC) || defined (CONFIG_WITH_DOT_MUST_MAKE) +set_file_variables (struct file *file, int called_early) +#else +set_file_variables (struct file *file) +#endif +{ + struct dep *d; + const char *at, *percent, *star, *less; +#ifdef CONFIG_WITH_STRCACHE2 + const char *org_stem = file->stem; +#endif + +#ifndef NO_ARCHIVES + /* If the target is an archive member 'lib(member)', + then $@ is 'lib' and $% is 'member'. */ + + if (ar_name (file->name)) + { + unsigned int len; + const char *cp; + char *p; + + cp = strchr (file->name, '('); + p = alloca (cp - file->name + 1); + memcpy (p, file->name, cp - file->name); + p[cp - file->name] = '\0'; + at = p; + len = strlen (cp + 1); + p = alloca (len); + memcpy (p, cp + 1, len - 1); + p[len - 1] = '\0'; + percent = p; + } + else +#endif /* NO_ARCHIVES. */ + { + at = file->name; + percent = ""; + } + + /* $* is the stem from an implicit or static pattern rule. */ + if (file->stem == 0) + { + /* In Unix make, $* is set to the target name with + any suffix in the .SUFFIXES list stripped off for + explicit rules. We store this in the 'stem' member. */ + const char *name; + unsigned int len; + +#ifndef NO_ARCHIVES + if (ar_name (file->name)) + { + name = strchr (file->name, '(') + 1; + len = strlen (name) - 1; + } + else +#endif + { + name = file->name; +#ifndef CONFIG_WITH_STRCACHE2 + len = strlen (name); +#else + len = strcache2_get_len (&file_strcache, name); +#endif + } + +#ifndef CONFIG_WITH_STRCACHE2 + for (d = enter_file (strcache_add (".SUFFIXES"))->deps; d ; d = d->next) + { + unsigned int slen = strlen (dep_name (d)); +#else + for (d = enter_file (suffixes_strcached)->deps; d ; d = d->next) + { + unsigned int slen = strcache2_get_len (&file_strcache, dep_name (d)); +#endif + if (len > slen && strneq (dep_name (d), name + (len - slen), slen)) + { + file->stem = strcache_add_len (name, len - slen); + break; + } + } + if (d == 0) + file->stem = ""; + } + star = file->stem; + + /* $< is the first not order-only dependency. */ + less = ""; + for (d = file->deps; d != 0; d = d->next) + if (!d->ignore_mtime) + { + if (!d->need_2nd_expansion) + less = dep_name (d); + break; + } + + if (file->cmds == default_file->cmds) + /* This file got its commands from .DEFAULT. + In this case $< is the same as $@. */ + less = at; + +#define DEFINE_VARIABLE(name, len, value) \ + (void) define_variable_for_file (name,len,value,o_automatic,0,file) + + /* Define the variables. */ + +#ifndef CONFIG_WITH_RDONLY_VARIABLE_VALUE + DEFINE_VARIABLE ("<", 1, less); + DEFINE_VARIABLE ("*", 1, star); + DEFINE_VARIABLE ("@", 1, at); + DEFINE_VARIABLE ("%", 1, percent); +#else /* CONFIG_WITH_RDONLY_VARIABLE_VALUE */ +# define DEFINE_VARIABLE_RO_VAL(name, len, value, value_len) \ + define_variable_in_set((name), (len), (value), (value_len), -1, \ + (o_automatic), 0, (file)->variables->set, NILF) + + if (*less == '\0') + DEFINE_VARIABLE_RO_VAL ("<", 1, "", 0); + else if (less != at || at == file->name) + DEFINE_VARIABLE_RO_VAL ("<", 1, less, strcache_get_len (less)); + else + DEFINE_VARIABLE ("<", 1, less); + + if (*star == '\0') + DEFINE_VARIABLE_RO_VAL ("*", 1, "", 0); + else if (file->stem != org_stem) + DEFINE_VARIABLE_RO_VAL ("*", 1, star, strcache_get_len (star)); + else + DEFINE_VARIABLE ("*", 1, star); + + if (at == file->name) + DEFINE_VARIABLE_RO_VAL ("@", 1, at, strcache_get_len (at)); + else + DEFINE_VARIABLE ("@", 1, at); + + if (*percent == '\0') + DEFINE_VARIABLE_RO_VAL ("%", 1, "", 0); + else + DEFINE_VARIABLE ("%", 1, percent); +#endif /* CONFIG_WITH_RDONLY_VARIABLE_VALUE */ + +#if defined(CONFIG_WITH_COMMANDS_FUNC) || defined (CONFIG_WITH_DOT_MUST_MAKE) + /* The $^, $+, $? and $| variables should not be set if we're called + early by a .MUST_MAKE invocation or $(commands ). */ + if (called_early) + return; +#endif + + /* Compute the values for $^, $+, $?, and $|. */ +#ifdef CONFIG_WITH_LAZY_DEPS_VARS + /* Lazy doesn't work for double colon rules with multiple files with + commands, nor for files that has been thru rehash_file() (vpath). */ + if ( ( file->double_colon + && ( file->double_colon != file + || file->last != file)) + || file->name != file->hname) /* XXX: Rehashed files should be fixable! */ +#endif + { + static char *plus_value=0, *bar_value=0, *qmark_value=0; + static unsigned int plus_max=0, bar_max=0, qmark_max=0; + + unsigned int qmark_len, plus_len, bar_len; + char *cp; + char *caret_value; + char *qp; + char *bp; + unsigned int len; + + struct hash_table dep_hash; + void **slot; + + /* Compute first the value for $+, which is supposed to contain + duplicate dependencies as they were listed in the makefile. */ + + plus_len = 0; + bar_len = 0; + for (d = file->deps; d != 0; d = d->next) + { + if (!d->need_2nd_expansion) + { + if (d->ignore_mtime) +#ifndef CONFIG_WITH_STRCACHE2 + bar_len += strlen (dep_name (d)) + 1; +#else + bar_len += strcache2_get_len (&file_strcache, dep_name (d)) + 1; +#endif + else +#ifndef CONFIG_WITH_STRCACHE2 + plus_len += strlen (dep_name (d)) + 1; +#else + plus_len += strcache2_get_len (&file_strcache, dep_name (d)) + 1; +#endif + } + } + + if (bar_len == 0) + bar_len++; + if (plus_len == 0) + plus_len++; + + if (plus_len > plus_max) + plus_value = xrealloc (plus_value, plus_max = plus_len); + + cp = plus_value; + + qmark_len = plus_len + 1; /* Will be this or less. */ + for (d = file->deps; d != 0; d = d->next) + if (! d->ignore_mtime && ! d->need_2nd_expansion) + { + const char *c = dep_name (d); + +#ifndef NO_ARCHIVES + if (ar_name (c)) + { + c = strchr (c, '(') + 1; + len = strlen (c) - 1; + } + else +#endif +#ifndef CONFIG_WITH_STRCACHE2 + len = strlen (c); +#else + len = strcache2_get_len (&file_strcache, c); +#endif + + memcpy (cp, c, len); + cp += len; + *cp++ = FILE_LIST_SEPARATOR; + if (! (d->changed || always_make_flag)) + qmark_len -= len + 1; /* Don't space in $? for this one. */ + } + + /* Kill the last space and define the variable. */ + + cp[cp > plus_value ? -1 : 0] = '\0'; + DEFINE_VARIABLE ("+", 1, plus_value); + + /* Compute the values for $^, $?, and $|. */ + + cp = caret_value = plus_value; /* Reuse the buffer; it's big enough. */ + + if (qmark_len > qmark_max) + qmark_value = xrealloc (qmark_value, qmark_max = qmark_len); + qp = qmark_value; + + if (bar_len > bar_max) + bar_value = xrealloc (bar_value, bar_max = bar_len); + bp = bar_value; + + /* Make sure that no dependencies are repeated in $^, $?, and $|. It + would be natural to combine the next two loops but we can't do it + because of a situation where we have two dep entries, the first + is order-only and the second is normal (see below). */ + + hash_init (&dep_hash, 500, dep_hash_1, dep_hash_2, dep_hash_cmp); + + for (d = file->deps; d != 0; d = d->next) + { + if (d->need_2nd_expansion) + continue; + + slot = hash_find_slot (&dep_hash, d); + if (HASH_VACANT (*slot)) + hash_insert_at (&dep_hash, d, slot); + else + { + /* Check if the two prerequisites have different ignore_mtime. + If so then we need to "upgrade" one that is order-only. */ + + struct dep* hd = (struct dep*) *slot; + + if (d->ignore_mtime != hd->ignore_mtime) + d->ignore_mtime = hd->ignore_mtime = 0; + } + } + + for (d = file->deps; d != 0; d = d->next) + { + const char *c; + + if (d->need_2nd_expansion || hash_find_item (&dep_hash, d) != d) + continue; + + c = dep_name (d); +#ifndef NO_ARCHIVES + if (ar_name (c)) + { + c = strchr (c, '(') + 1; + len = strlen (c) - 1; + } + else +#endif +#ifndef CONFIG_WITH_STRCACHE2 + len = strlen (c); +#else + len = strcache2_get_len (&file_strcache, c); +#endif + + if (d->ignore_mtime) + { + memcpy (bp, c, len); + bp += len; + *bp++ = FILE_LIST_SEPARATOR; + } + else + { + memcpy (cp, c, len); + cp += len; + *cp++ = FILE_LIST_SEPARATOR; + if (d->changed || always_make_flag) + { + memcpy (qp, c, len); + qp += len; + *qp++ = FILE_LIST_SEPARATOR; + } + } + } + + hash_free (&dep_hash, 0); + + /* Kill the last spaces and define the variables. */ + + cp[cp > caret_value ? -1 : 0] = '\0'; + DEFINE_VARIABLE ("^", 1, caret_value); + + qp[qp > qmark_value ? -1 : 0] = '\0'; + DEFINE_VARIABLE ("?", 1, qmark_value); + + bp[bp > bar_value ? -1 : 0] = '\0'; + DEFINE_VARIABLE ("|", 1, bar_value); + } +#undef DEFINE_VARIABLE +} + +/* Chop CMDS up into individual command lines if necessary. + Also set the 'lines_flags' and 'any_recurse' members. */ + +void +chop_commands (struct commands *cmds) +{ + unsigned int nlines, idx; + char **lines; + + /* If we don't have any commands, + or we already parsed them, never mind. */ + + if (!cmds || cmds->command_lines != 0) + return; + + /* Chop CMDS->commands up into lines in CMDS->command_lines. */ + + if (one_shell) + { + int l = strlen (cmds->commands); + + nlines = 1; + lines = xmalloc (nlines * sizeof (char *)); + lines[0] = xstrdup (cmds->commands); + + /* Strip the trailing newline. */ + if (l > 0 && lines[0][l-1] == '\n') + lines[0][l-1] = '\0'; + } + else + { + const char *p; + + nlines = 5; + lines = xmalloc (nlines * sizeof (char *)); + idx = 0; + p = cmds->commands; + while (*p != '\0') + { + const char *end = p; + find_end:; + end = strchr (end, '\n'); + if (end == 0) + end = p + strlen (p); + else if (end > p && end[-1] == '\\') + { + int backslash = 1; + const char *b; + for (b = end - 2; b >= p && *b == '\\'; --b) + backslash = !backslash; + if (backslash) + { + ++end; + goto find_end; + } + } + + if (idx == nlines) + { + nlines += 2; + lines = xrealloc (lines, nlines * sizeof (char *)); + } + lines[idx++] = xstrndup (p, end - p); + p = end; + if (*p != '\0') + ++p; + } + + if (idx != nlines) + { + nlines = idx; + lines = xrealloc (lines, nlines * sizeof (char *)); + } + } + + /* Finally, set the corresponding CMDS->lines_flags elements and the + CMDS->any_recurse flag. */ + + if (nlines > USHRT_MAX) + ON (fatal, &cmds->fileinfo, _("Recipe has too many lines (%ud)"), nlines); + + cmds->ncommand_lines = nlines; + cmds->command_lines = lines; + + cmds->any_recurse = 0; +#ifndef CONFIG_WITH_COMMANDS_FUNC + cmds->lines_flags = xmalloc (nlines); +#else + cmds->lines_flags = xmalloc (nlines * sizeof (cmds->lines_flags[0])); +#endif + + for (idx = 0; idx < nlines; ++idx) + { + unsigned char flags = 0; + const char *p = lines[idx]; + + while (ISBLANK (*p) || *p == '-' || *p == '@' || *p == '+' IF_WITH_COMMANDS_FUNC(|| *p == '%')) + switch (*(p++)) + { + case '+': + flags |= COMMANDS_RECURSE; + break; + case '@': + flags |= COMMANDS_SILENT; + break; + case '-': + flags |= COMMANDS_NOERROR; + break; +#ifdef CONFIG_WITH_COMMANDS_FUNC + case '%': + flags |= COMMAND_GETTER_SKIP_IT; + break; +#endif + } + + /* If no explicit '+' was given, look for MAKE variable references. */ + if (!(flags & COMMANDS_RECURSE) +#ifndef KMK + && (strstr (p, "$(MAKE)") != 0 || strstr (p, "${MAKE}") != 0)) +#else + && (strstr (p, "$(KMK)") != 0 || strstr (p, "${KMK}") != 0 || + strstr (p, "$(MAKE)") != 0 || strstr (p, "${MAKE}") != 0)) +#endif + flags |= COMMANDS_RECURSE; + +#ifdef CONFIG_WITH_KMK_BUILTIN + /* check if kmk builtin command */ + if (!strncmp(p, "kmk_builtin_", sizeof("kmk_builtin_") - 1)) + flags |= COMMANDS_KMK_BUILTIN; +#endif + + cmds->lines_flags[idx] = flags; + cmds->any_recurse |= flags & COMMANDS_RECURSE ? 1 : 0; + } +} + +#ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS +/* This is for saving memory in func_commands. */ +void +free_chopped_commands (struct commands *cmds) +{ + if ( cmds + && cmds->command_lines != 0 + && cmds->refs == 0) + { + unsigned idx = cmds->ncommand_lines; + while (idx-- > 0) + free (cmds->command_lines[idx]); + free (cmds->command_lines); + free (cmds->lines_flags); + cmds->command_lines = 0; + cmds->lines_flags = 0; + cmds->ncommand_lines = 0; + } +} + +#endif /* CONFIG_WITH_MEMORY_OPTIMIZATIONS */ +/* Execute the commands to remake FILE. If they are currently executing, + return or have already finished executing, just return. Otherwise, + fork off a child process to run the first command line in the sequence. */ + +void +execute_file_commands (struct file *file) +{ + const char *p; + + /* Don't go through all the preparations if + the commands are nothing but whitespace. */ + + for (p = file->cmds->commands; *p != '\0'; ++p) + if (!ISSPACE (*p) && *p != '-' && *p != '@' && *p != '+') + break; + if (*p == '\0') + { + /* If there are no commands, assume everything worked. */ +#ifdef CONFIG_WITH_EXTENDED_NOTPARALLEL + file->command_flags |= COMMANDS_NO_COMMANDS; +#endif + set_command_state (file, cs_running); + file->update_status = us_success; + notice_finished_file (file); + return; + } + + /* First set the automatic variables according to this file. */ + + initialize_file_variables (file, 0); + +#if defined(CONFIG_WITH_COMMANDS_FUNC) || defined (CONFIG_WITH_DOT_MUST_MAKE) + set_file_variables (file, 0 /* final call */); +#else + set_file_variables (file); +#endif + + /* If this is a loaded dynamic object, unload it before remaking. + Some systems don't support overwriting a loaded object. */ + if (file->loaded) + unload_file (file->name); + + /* Start the commands running. */ + new_job (file); +} + +/* This is set while we are inside fatal_error_signal, + so things can avoid nonreentrant operations. */ + +int handling_fatal_signal = 0; + +/* Handle fatal signals. */ + +RETSIGTYPE +fatal_error_signal (int sig) +{ +#ifdef __MSDOS__ + extern int dos_status, dos_command_running; + + if (dos_command_running) + { + /* That was the child who got the signal, not us. */ + dos_status |= (sig << 8); + return; + } + remove_intermediates (1); + exit (EXIT_FAILURE); +#else /* not __MSDOS__ */ +#ifdef _AMIGA + remove_intermediates (1); + if (sig == SIGINT) + fputs (_("*** Break.\n"), stderr); + + exit (10); +#else /* not Amiga */ +#if defined (WINDOWS32) && !defined (CONFIG_NEW_WIN32_CTRL_EVENT) + extern HANDLE main_thread; + + /* Windows creates a sperate thread for handling Ctrl+C, so we need + to suspend the main thread, or else we will have race conditions + when both threads call reap_children. */ + if (main_thread) + { + DWORD susp_count = SuspendThread (main_thread); + + if (susp_count != 0) + fprintf (stderr, "SuspendThread: suspend count = %ld\n", susp_count); + else if (susp_count == (DWORD)-1) + { + DWORD ierr = GetLastError (); + + fprintf (stderr, "SuspendThread: error %ld: %s\n", + ierr, map_windows32_error_to_string (ierr)); + } + } +#endif + handling_fatal_signal = 1; + + /* Set the handling for this signal to the default. + It is blocked now while we run this handler. */ + signal (sig, SIG_DFL); + + /* A termination signal won't be sent to the entire + process group, but it means we want to kill the children. */ + + if (sig == SIGTERM) + { + struct child *c; + for (c = children; c != 0; c = c->next) + if (!c->remote) +# if defined (CONFIG_NEW_WIN_CHILDREN) && defined (WINDOWS32) + MkWinChildKill (c->pid, SIGTERM, c); +# else + (void) kill (c->pid, SIGTERM); +# endif + } + + /* If we got a signal that means the user + wanted to kill make, remove pending targets. */ + + if (sig == SIGTERM || sig == SIGINT +#ifdef SIGHUP + || sig == SIGHUP +#endif +#ifdef SIGQUIT + || sig == SIGQUIT +#endif + ) + { + struct child *c; + + /* Remote children won't automatically get signals sent + to the process group, so we must send them. */ + for (c = children; c != 0; c = c->next) + if (c->remote) + (void) remote_kill (c->pid, sig); + + for (c = children; c != 0; c = c->next) + delete_child_targets (c); + + /* Clean up the children. We don't just use the call below because + we don't want to print the "Waiting for children" message. */ + while (job_slots_used > 0) + reap_children (1, 0); + } + else + /* Wait for our children to die. */ + while (job_slots_used > 0) + reap_children (1, 1); + + /* Delete any non-precious intermediate files that were made. */ + + remove_intermediates (1); +#ifdef SIGQUIT + if (sig == SIGQUIT) + /* We don't want to send ourselves SIGQUIT, because it will + cause a core dump. Just exit instead. */ + exit (MAKE_TROUBLE); +#endif + +#ifdef WINDOWS32 +# ifndef CONFIG_NEW_WIN32_CTRL_EVENT + if (main_thread) + CloseHandle (main_thread); +# endif /* !CONFIG_NEW_WIN32_CTRL_EVENT */ + /* Cannot call W32_kill with a pid (it needs a handle). The exit + status of 130 emulates what happens in Bash. */ + exit (130); +#else + /* Signal the same code; this time it will really be fatal. The signal + will be unblocked when we return and arrive then to kill us. */ + if (kill (getpid (), sig) < 0) + pfatal_with_name ("kill"); +#endif /* not WINDOWS32 */ +#endif /* not Amiga */ +#endif /* not __MSDOS__ */ +} + +/* Delete FILE unless it's precious or not actually a file (phony), + and it has changed on disk since we last stat'd it. */ + +static void +delete_target (struct file *file, const char *on_behalf_of) +{ + struct stat st; + int e; + + if (file->precious || file->phony) + return; +#ifdef CONFIG_WITH_EXPLICIT_MULTITARGET + assert (!file->multi_maybe); +#endif + +#ifndef NO_ARCHIVES + if (ar_name (file->name)) + { + time_t file_date = (file->last_mtime == NONEXISTENT_MTIME + ? (time_t) -1 + : (time_t) FILE_TIMESTAMP_S (file->last_mtime)); + if (ar_member_date (file->name) != file_date) + { + if (on_behalf_of) + OSS (error, NILF, + _("*** [%s] Archive member '%s' may be bogus; not deleted"), + on_behalf_of, file->name); + else + OS (error, NILF, + _("*** Archive member '%s' may be bogus; not deleted"), + file->name); + } + return; + } +#endif + + EINTRLOOP (e, stat (file->name, &st)); + if (e == 0 + && S_ISREG (st.st_mode) + && FILE_TIMESTAMP_STAT_MODTIME (file->name, st) != file->last_mtime) + { + if (on_behalf_of) + OSS (error, NILF, + _("*** [%s] Deleting file '%s'"), on_behalf_of, file->name); + else + OS (error, NILF, _("*** Deleting file '%s'"), file->name); + if (unlink (file->name) < 0 + && errno != ENOENT) /* It disappeared; so what. */ + perror_with_name ("unlink: ", file->name); + } +} + + +/* Delete all non-precious targets of CHILD unless they were already deleted. + Set the flag in CHILD to say they've been deleted. */ + +void +delete_child_targets (struct child *child) +{ + struct dep *d; + + if (child->deleted) + return; + + /* Delete the target file if it changed. */ + delete_target (child->file, NULL); + + /* Also remove any non-precious targets listed in the 'also_make' member. */ + for (d = child->file->also_make; d != 0; d = d->next) + delete_target (d->file, child->file->name); + +#ifdef CONFIG_WITH_EXPLICIT_MULTITARGET + /* Also remove any multi target siblings, except for the 'maybe' ones (we + handle that here) and precious ones (delete_target deals with that). + Note that CHILD is always the multi target head (see remake.c). */ + if (child->file == child->file->multi_head) + { + struct file *f2; + for (f2 = child->file->multi_next; f2; f2 = f2->multi_next) + if (!f2->multi_maybe) + delete_target (f2, child->file->name); + } +#endif + + child->deleted = 1; +} + +/* Print out the commands in CMDS. */ + +void +print_commands (const struct commands *cmds) +{ + const char *s; + + fputs (_("# recipe to execute"), stdout); + + if (cmds->fileinfo.filenm == 0) + puts (_(" (built-in):")); + else + printf (_(" (from '%s', line %lu):\n"), + cmds->fileinfo.filenm, cmds->fileinfo.lineno); + + s = cmds->commands; + while (*s != '\0') + { + const char *end; + int bs; + + /* Print one full logical recipe line: find a non-escaped newline. */ + for (end = s, bs = 0; *end != '\0'; ++end) + { + if (*end == '\n' && !bs) + break; + + bs = *end == '\\' ? !bs : 0; + } + + printf ("%c%.*s\n", cmd_prefix, (int) (end - s), s); + + s = end + (end[0] == '\n'); + } +} diff --git a/src/kmk/commands.h b/src/kmk/commands.h new file mode 100644 index 0000000..f06367b --- /dev/null +++ b/src/kmk/commands.h @@ -0,0 +1,70 @@ +/* Definition of data structures describing shell commands for GNU Make. +Copyright (C) 1988-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +/* Structure that gives the commands to make a file + and information about where these commands came from. */ + +struct commands + { + floc fileinfo; /* Where commands were defined. */ + char *commands; /* Commands text. */ + char **command_lines; /* Commands chopped up into lines. */ +#ifdef CONFIG_WITH_COMMANDS_FUNC + unsigned short *lines_flags;/* One set of flag bits for each line. */ +#else + unsigned char *lines_flags; /* One set of flag bits for each line. */ +#endif + unsigned short ncommand_lines;/* Number of command lines. */ + char recipe_prefix; /* Recipe prefix for this command set. */ + unsigned int any_recurse:1; /* Nonzero if any 'lines_flags' elt has */ + /* the COMMANDS_RECURSE bit set. */ +#ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS + int refs; /* References. */ +#endif + }; + +/* Bits in 'lines_flags'. */ +#define COMMANDS_RECURSE 1 /* Recurses: + or $(MAKE). */ +#define COMMANDS_SILENT 2 /* Silent: @. */ +#define COMMANDS_NOERROR 4 /* No errors: -. */ +#ifdef CONFIG_WITH_EXTENDED_NOTPARALLEL +# define COMMANDS_NOTPARALLEL 32 /* kmk: The commands must be executed alone. */ +# define COMMANDS_NO_COMMANDS 64 /* kmk: No commands. */ +#endif +#ifdef CONFIG_WITH_KMK_BUILTIN +# define COMMANDS_KMK_BUILTIN 128 /* kmk: kmk builtin command. */ +#endif +#ifdef CONFIG_WITH_COMMANDS_FUNC +# define COMMAND_GETTER_SKIP_IT 256 /* $(commands target) skips this: % */ +#endif + +RETSIGTYPE fatal_error_signal (int sig); +void execute_file_commands (struct file *file); +void print_commands (const struct commands *cmds); +void delete_child_targets (struct child *child); +void chop_commands (struct commands *cmds); +#ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS +void free_chopped_commands (struct commands *cmd); +#endif +#if defined(CONFIG_WITH_COMMANDS_FUNC) || defined (CONFIG_WITH_DOT_MUST_MAKE) +void set_file_variables (struct file *file, int called_early); +#else +void set_file_variables (struct file *file); +#endif +#ifdef CONFIG_WITH_LAZY_DEPS_VARS +struct dep *create_uniqute_deps_chain (struct dep *deps); +#endif + diff --git a/src/kmk/config.ami.template b/src/kmk/config.ami.template new file mode 100644 index 0000000..4c5bb78 --- /dev/null +++ b/src/kmk/config.ami.template @@ -0,0 +1,337 @@ +/* config.h -- hand-massaged for Amiga -*-C-*- +Copyright (C) 1995-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +/* Define if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +/* #undef _ALL_SOURCE */ +#endif + +/* Define if using alloca.c. */ +#define C_ALLOCA + +/* Define if the closedir function returns void instead of int. */ +/* #undef CLOSEDIR_VOID */ + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. + This function is required for alloca.c support on those systems. */ +/* #undef CRAY_STACKSEG_END */ + +/* Define for DGUX with . */ +/* #undef DGUX */ + +/* Define if the 'getloadavg' function needs to be run setuid or setgid. */ +/* #undef GETLOADAVG_PRIVILEGED */ + +/* Define to 'unsigned long' or 'unsigned long long' + if doesn't define. */ +#define uintmax_t unsigned long + +/* Define to 'int' if doesn't define. */ +#define gid_t int + +/* Define if you have alloca, as a function or macro. */ +/* #undef HAVE_ALLOCA */ + +/* Define if you have and it should be used (not on Ultrix). */ +/* #undef HAVE_ALLOCA_H */ + +/* Define if your system has a working fnmatch function. */ +/* #undef HAVE_FNMATCH */ + +/* Define if your system has its own 'getloadavg' function. */ +/* #undef HAVE_GETLOADAVG */ + +/* Define if you have the getmntent function. */ +/* #undef HAVE_GETMNTENT */ + +/* Embed GNU Guile support */ +/* #undef HAVE_GUILE */ + +/* Define if the 'long double' type works. */ +/* #undef HAVE_LONG_DOUBLE */ + +/* Define if you support file names longer than 14 characters. */ +#define HAVE_LONG_FILE_NAMES 1 + +/* Define if you have a working 'mmap' system call. */ +/* #undef HAVE_MMAP */ + +/* Define if system calls automatically restart after interruption + by a signal. */ +/* #undef HAVE_RESTARTABLE_SYSCALLS */ + +/* Define if your struct stat has st_blksize. */ +/* #undef HAVE_ST_BLKSIZE */ + +/* Define if your struct stat has st_blocks. */ +/* #undef HAVE_ST_BLOCKS */ + +/* Define if you have the strcoll function and it is properly defined. */ +#define HAVE_STRCOLL 1 + +/* Define if your struct stat has st_rdev. */ +#define HAVE_ST_RDEV 1 + +/* Define if you have the strftime function. */ +#define HAVE_STRFTIME 1 + +/* Define if you have that is POSIX.1 compatible. */ +/* #undef HAVE_SYS_WAIT_H */ + +/* Define if your struct tm has tm_zone. */ +/* #undef HAVE_TM_ZONE */ + +/* Define if you don't have tm_zone but do have the external array + tzname. */ +#define HAVE_TZNAME 1 + +/* Define if you have . */ +#define HAVE_UNISTD_H 1 + +/* Define if utime(file, NULL) sets file's timestamp to the present. */ +/* #undef HAVE_UTIME_NULL */ + +/* Define if you have the wait3 system call. */ +/* #undef HAVE_WAIT3 */ + +/* Define if on MINIX. */ +/* #undef _MINIX */ + +/* Define if your struct nlist has an n_un member. */ +/* #undef NLIST_NAME_UNION */ + +/* Define if you have . */ +/* #undef NLIST_STRUCT */ + +/* Define if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Define to 'int' if doesn't define. */ +#define pid_t int + +/* Define if the system does not provide POSIX.1 features except + with this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define if you need to in order for stat and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Define if the setvbuf function takes the buffering type as its second + argument and the buffer pointer as the third, as on System V + before release 3. */ +/* #undef SETVBUF_REVERSED */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +#define STACK_DIRECTION -1 + +/* Define if the 'S_IS*' macros in do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS + +/* Define on System V Release 4. */ +/* #undef SVR4 */ + +/* Define if 'sys_siglist' is declared by . */ +/* #undef SYS_SIGLIST_DECLARED */ + +/* Define to 'int' if doesn't define. */ +#define uid_t int + +/* Define for Encore UMAX. */ +/* #undef UMAX */ + +/* Define for Encore UMAX 4.3 that has + instead of . */ +/* #undef UMAX4_3 */ + +/* Name of this package (needed by automake) */ +#define PACKAGE "%PACKAGE%" + +/* Version of this package (needed by automake) */ +#define VERSION "%VERSION%" + +/* Define to the name of the SCCS 'get' command. */ +#define SCCS_GET "get" + +/* Define this if the SCCS 'get' command understands the '-G' option. */ +/* #undef SCCS_GET_MINUS_G */ + +/* Define this to enable job server support in GNU make. */ +/* #undef MAKE_JOBSERVER */ + +/* Define to be the nanoseconds member of struct stat's st_mtim, + if it exists. */ +/* #undef ST_MTIM_NSEC */ + +/* Define this if the C library defines the variable 'sys_siglist'. */ +/* #undef HAVE_SYS_SIGLIST */ + +/* Define this if the C library defines the variable '_sys_siglist'. */ +/* #undef HAVE__SYS_SIGLIST */ + +/* Define this if you have the 'union wait' type in . */ +/* #undef HAVE_UNION_WAIT */ + +/* Define if you have the dup2 function. */ +/* #undef HAVE_DUP2 */ + +/* Define if you have the getcwd function. */ +#define HAVE_GETCWD 1 + +/* Define if you have the getgroups function. */ +/* #undef HAVE_GETGROUPS */ + +/* Define if you have the gethostbyname function. */ +/* #undef HAVE_GETHOSTBYNAME */ + +/* Define if you have the gethostname function. */ +/* #undef HAVE_GETHOSTNAME */ + +/* Define if you have the memmove function. */ +#define HAVE_MEMMOVE 1 + +/* Define if you have the mktemp function. */ +#define HAVE_MKTEMP 1 + +/* Define if you have the psignal function. */ +/* #undef HAVE_PSIGNAL */ + +/* Define if you have the pstat_getdynamic function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ + +/* Define if you have the setegid function. */ +/* #undef HAVE_SETEGID */ + +/* Define if you have the seteuid function. */ +/* #undef HAVE_SETEUID */ + +/* Define if you have the setlinebuf function. */ +/* #undef HAVE_SETLINEBUF */ + +/* Define if you have the setregid function. */ +/* #undef HAVE_SETREGID */ + +/* Define if you have the setreuid function. */ +/* #undef HAVE_SETREUID */ + +/* Define if you have the sigsetmask function. */ +/* #undef HAVE_SIGSETMASK */ + +/* Define if you have the socket function. */ +/* #undef HAVE_SOCKET */ + +/* Define to 1 if you have the strcasecmp function. */ +/* #undef HAVE_STRCASECMP */ + +/* Define to 1 if you have the strcmpi function. */ +/* #undef HAVE_STRCMPI */ + +/* Define to 1 if you have the stricmp function. */ +/* #undef HAVE_STRICMP */ + +/* Define if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define if you have the strsignal function. */ +/* #undef HAVE_STRSIGNAL */ + +/* Define if you have the wait3 function. */ +/* #undef HAVE_WAIT3 */ + +/* Define if you have the waitpid function. */ +/* #undef HAVE_WAITPID */ + +/* Define if you have the header file. */ +#define HAVE_DIRENT_H 1 + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_MACH_MACH_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_MEMORY_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_NDIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_STDLIB_H */ + +/* Define if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_DIR_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_PARAM_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_TIMEB_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_WAIT_H */ + +/* Define if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the dgc library (-ldgc). */ +/* #undef HAVE_LIBDGC */ + +/* Define if you have the kstat library (-lkstat). */ +/* #undef HAVE_LIBKSTAT */ + +/* Define to 1 if you have the `isatty' function. */ +/* #undef HAVE_ISATTY */ + +/* Define to 1 if you have the `ttyname' function. */ +/* #undef HAVE_TTYNAME */ + +/* Define if you have the sun library (-lsun). */ +/* #undef HAVE_LIBSUN */ + +/* Output sync sypport */ +#define NO_OUTPUT_SYNC + +/* Define for Case Insensitve behavior */ +#define HAVE_CASE_INSENSITIVE_FS + +/* Build host information. */ +#define MAKE_HOST "Amiga" diff --git a/src/kmk/config.h-vms.template b/src/kmk/config.h-vms.template new file mode 100644 index 0000000..2a4a943 --- /dev/null +++ b/src/kmk/config.h-vms.template @@ -0,0 +1,432 @@ +/* config.h-vms. Generated by hand by Klaus Kämpf -*-C-*- + +Copyright (C) 1996-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +/* config.h. Generated automatically by configure. */ +/* config.h.in. Generated automatically from configure.ac by autoheader. */ + +/* Pull in types.h here to get __CRTL_VER defined for old versions of the + compiler which don't define it. */ +#ifdef __DECC +# include +#endif + +/* Define to 1 if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +/* #undef _ALL_SOURCE */ +#endif + +/* Define to 1 if NLS is requested. */ +/* #undef ENABLE_NLS */ + +/* Define as 1 if you have dcgettext. */ +/* #undef HAVE_DCGETTEXT */ + +/* Define as 1 if you have gettext and don't want to use GNU gettext. */ +/* #undef HAVE_GETTEXT */ + +/* Embed GNU Guile support */ +/* #undef HAVE_GUILE */ + +/* Define to 1 if your locale.h file contains LC_MESSAGES. */ +/* #undef HAVE_LC_MESSAGES */ + +/* Define to the installation directory for locales. */ +#define LOCALEDIR "" + +/* Define as 1 if you have the stpcpy function. */ +/* #undef HAVE_STPCPY */ + +/* Define to 1 if the closedir function returns void instead of int. */ +/* #undef CLOSEDIR_VOID */ + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. + This function is required for alloca.c support on those systems. */ +/* #undef CRAY_STACKSEG_END */ + +/* Define for DGUX with . */ +/* #undef DGUX */ + +/* Define to 1 if the 'getloadavg' function needs to be run setuid or setgid. */ +/* #undef GETLOADAVG_PRIVILEGED */ + +/* Define to 'unsigned long' or 'unsigned long long' + if doesn't define. */ +#define uintmax_t unsigned long + +/* Define to 'int' if doesn't define. */ +/* #undef gid_t */ + +/* Define to 1 if you have alloca, as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have and it should be used (not on Ultrix). */ +/* #undef HAVE_ALLOCA_H */ + +/* Define to 1 if you have the fdopen function. */ +#define HAVE_FDOPEN 1 + +/* Define to 1 if your system has a working fnmatch function. */ +/* #undef HAVE_FNMATCH */ + +/* Define to 1 if your system has its own 'getloadavg' function. */ +/* #undef HAVE_GETLOADAVG */ + +/* Define to 1 if you have the getmntent function. */ +/* #undef HAVE_GETMNTENT */ + +/* Define to 1 if the 'long double' type works. */ +/* #undef HAVE_LONG_DOUBLE */ + +/* Define to 1 if you support file names longer than 14 characters. */ +#define HAVE_LONG_FILE_NAMES 1 + +/* Define to 1 if you have a working 'mmap' system call. */ +/* #undef HAVE_MMAP */ + +/* Define to 1 if system calls automatically restart after interruption + by a signal. */ +/* #undef HAVE_RESTARTABLE_SYSCALLS */ + +/* Define to 1 if your struct stat has st_blksize. */ +/* #undef HAVE_ST_BLKSIZE */ + +/* Define to 1 if your struct stat has st_blocks. */ +/* #undef HAVE_ST_BLOCKS */ + +/* Define to 1 if you have the strcoll function and it is properly defined. */ +/* #undef HAVE_STRCOLL */ + +/* Define to 1 if you have the strncasecmp' function. */ +#if __CRTL_VER >= 70000000 +#define HAVE_STRNCASECMP 1 +#endif + +/* Define to 1 if your struct stat has st_rdev. */ +/* #undef HAVE_ST_RDEV */ + +/* Define to 1 if you have the strftime function. */ +/* #undef HAVE_STRFTIME */ + +/* Define to 1 if you have that is POSIX.1 compatible. */ +/* #undef HAVE_SYS_WAIT_H */ + +/* Define to 1 if your struct tm has tm_zone. */ +/* #undef HAVE_TM_ZONE */ + +/* Define to 1 if you don't have tm_zone but do have the external array + tzname. */ +/* #undef HAVE_TZNAME */ + +/* Define to 1 if you have . */ +#ifdef __DECC +#define HAVE_UNISTD_H 1 +#endif + +/* Define to 1 if utime(file, NULL) sets file's timestamp to the present. */ +/* #undef HAVE_UTIME_NULL */ + +/* Define to 1 if you have the wait3 system call. */ +/* #undef HAVE_WAIT3 */ + +/* Define to 1 if on MINIX. */ +/* #undef _MINIX */ + +/* Define to 1 if your struct nlist has an n_un member. */ +/* #undef NLIST_NAME_UNION */ + +/* Define to 1 if you have . */ +/* #undef NLIST_STRUCT */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Define to 'int' if doesn't define. */ +/* I assume types.h is available for all 5.0 cc/cxx compilers */ +#if __DECC_VER < 50090000 +#define pid_t int +#endif + +/* Define to 1 if the system does not provide POSIX.1 features except + with this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to 1 if you need to in order for stat and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Define to 1 if the setvbuf function takes the buffering type as its second + argument and the buffer pointer as the third, as on System V + before release 3. */ +/* #undef SETVBUF_REVERSED */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if the 'S_IS*' macros in do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define to 1 if you have the ANSI C header files. */ +/* #undef STDC_HEADERS */ + +/* Define on System V Release 4. */ +/* #undef SVR4 */ + +/* Define to 1 if 'sys_siglist' is declared by . */ +/* #undef SYS_SIGLIST_DECLARED */ + +/* Define to 'int' if doesn't define. */ +#if __DECC_VER < 50090000 +#define uid_t int +#endif + +/* Define for Encore UMAX. */ +/* #undef UMAX */ + +/* Define for Encore UMAX 4.3 that has + instead of . */ +/* #undef UMAX4_3 */ + +/* Name of this package (needed by automake) */ +#define PACKAGE "%PACKAGE%" + +/* Version of this package (needed by automake) */ +#define VERSION "%VERSION%" + +/* Define to the name of the SCCS 'get' command. */ +/* #undef SCCS_GET */ + +/* Define this if the SCCS 'get' command understands the '-G' option. */ +/* #undef SCCS_GET_MINUS_G */ + +/* Define this to enable job server support in GNU make. */ +/* #undef MAKE_JOBSERVER */ + +/* Define to be the nanoseconds member of struct stat's st_mtim, + if it exists. */ +/* #undef ST_MTIM_NSEC */ + +/* Define to 1 if the C library defines the variable 'sys_siglist'. */ +/* #undefine HAVE_SYS_SIGLIST */ + +/* Define to 1 if the C library defines the variable '_sys_siglist'. */ +/* #undef HAVE__SYS_SIGLIST */ + +/* Define to 1 if you have the 'union wait' type in . */ +/* #undef HAVE_UNION_WAIT */ + +/* Define to 1 if you have the dup2 function. */ +#define HAVE_DUP2 1 + +/* Define to 1 if you have the getcwd function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the getgroups function. */ +/* #undef HAVE_GETGROUPS */ + +/* Define to 1 if you have the gethostbyname function. */ +/* #undef HAVE_GETHOSTBYNAME */ + +/* Define to 1 if you have the gethostname function. */ +/* #undef HAVE_GETHOSTNAME */ + +/* Define to 1 if you have the memmove function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the mktemp function. */ +#define HAVE_MKTEMP 1 + +/* Define to 1 if you have the psignal function. */ +/* #undef HAVE_PSIGNAL */ + +/* Define to 1 if you have the pstat_getdynamic function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ + +/* Define to 1 if you have the setegid function. */ +/* #undef HAVE_SETEGID */ + +/* Define to 1 if you have the seteuid function. */ +/* #undef HAVE_SETEUID */ + +/* Define to 1 if you have the setlinebuf function. */ +/* #undef HAVE_SETLINEBUF */ + +/* Define to 1 if you have the setregid function. */ +/* #undefine HAVE_SETREGID */ + +/* Define to 1 if you have the setreuid function. */ +/* #define HAVE_SETREUID */ + +/* Define to 1 if you have the sigsetmask function. */ +#define HAVE_SIGSETMASK 1 + +/* Define to 1 if you have the socket function. */ +/* #undef HAVE_SOCKET */ + +/* Define to 1 if you have the strcasecmp function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the strcmpi function. */ +/* #undef HAVE_STRCMPI */ + +/* Define to 1 if you have the stricmp function. */ +/* #undef HAVE_STRICMP */ + +/* Define to 1 if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the strsignal function. */ +/* #undef HAVE_STRSIGNAL */ + +/* Define to 1 if you have the wait3 function. */ +/* #undef HAVE_WAIT3 */ + +/* Define to 1 if you have the waitpid function. */ +/* #undef HAVE_WAITPID */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the header file. */ +#ifdef __DECC +#define HAVE_FCNTL_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACH_MACH_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MEMORY_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_PARAM_H */ + +/* Define to 1 if you have the header file. */ +#ifndef __GNUC__ +#define HAVE_SYS_TIMEB_H 1 +#endif + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_WAIT_H */ + +/* Define to 1 if you have the dgc library (-ldgc). */ +/* #undef HAVE_LIBDGC */ + +/* Define to 1 if you have the kstat library (-lkstat). */ +/* #undef HAVE_LIBKSTAT * + +/* Define to 1 if you have the sun library (-lsun). */ +/* #undef HAVE_LIBSUN */ + +/* Define to 1 if you have the `isatty' function. */ +/* #undef HAVE_ISATTY */ + +/* Define to 1 if you have the `ttyname' function. */ +/* #undef HAVE_TTYNAME */ + +/* Use high resolution file timestamps if nonzero. */ +#define FILE_TIMESTAMP_HI_RES 0 + +/* Define for case insensitve filenames */ +#define HAVE_CASE_INSENSITIVE_FS 1 + +/* VMS specific, define it if you want to use case sensitive targets */ +/* #undef WANT_CASE_SENSITIVE_TARGETS */ + +/* VMS specific, V7.0 has opendir() and friends, so it's undefined */ +/* If you want to use non-VMS code for opendir() etc. on V7.0 and greater + define the first or both macros AND change the compile command to get the + non-VMS versions linked: (prefix=(all,except=(opendir,... */ +/* #undef HAVE_VMSDIR_H */ +/* #undef _DIRENT_HAVE_D_NAMLEN */ + +/* On older systems without 7.0 backport of CRTL use non-VMS code for opendir() etc. */ +#if __CRTL_VER < 70000000 +# define HAVE_VMSDIR_H 1 +#endif + +#if defined(HAVE_VMSDIR_H) && defined(HAVE_DIRENT_H) +#undef HAVE_DIRENT_H +#endif + +#define HAVE_STDLIB_H 1 +#define INCLUDEDIR "sys$sysroot:[syslib]" +#define LIBDIR "sys$sysroot:[syslib]" + +/* Don't use RTL functions of OpenVMS */ +#ifdef __DECC +#include +#include +#define getopt gnu_getopt +#define optarg gnu_optarg +#define optopt gnu_optopt +#define optind gnu_optind +#define opterr gnu_opterr +#define globfree gnu_globfree +#define glob gnu_glob +#endif + +/* Define if using alloca.c. */ +/* #undef C_ALLOCA */ +/* maybe this should be placed into makeint.h */ +#if defined(__VAX) && defined(__DECC) +#define alloca(n) __ALLOCA(n) +#endif + +/* Output sync sypport */ +#define NO_OUTPUT_SYNC + +/* Define to 1 to write even short single-line actions into a VMS/DCL command + file; this also enables exporting make environment variables into the + (sub-)process, which executes the action. + The usual make rules apply whether a shell variable - here a DCL symbol or + VMS logical [see CRTL getenv()] - is added to the make environment and + is exported. */ +#define USE_DCL_COM_FILE 1 + +/* Build host information. */ +#define MAKE_HOST "VMS" diff --git a/src/kmk/config.h.W32.template b/src/kmk/config.h.W32.template new file mode 100644 index 0000000..73446e0 --- /dev/null +++ b/src/kmk/config.h.W32.template @@ -0,0 +1,532 @@ +/* config.h.W32 -- hand-massaged config.h file for Windows builds -*-C-*- + +Copyright (C) 1996-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +/* Suppress some Visual C++ warnings. + Maybe after the code cleanup for ISO C we can remove some/all of these. */ +#if _MSC_VER > 1000 +# pragma warning(disable:4100) /* unreferenced formal parameter */ +# pragma warning(disable:4102) /* unreferenced label */ +# pragma warning(disable:4127) /* conditional expression is constant */ +# pragma warning(disable:4131) /* uses old-style declarator */ +# pragma warning(disable:4702) /* unreachable code */ +# define _CRT_SECURE_NO_WARNINGS /* function or variable may be unsafe */ +# define _CRT_NONSTDC_NO_WARNINGS /* functions w/o a leading underscore */ +#endif + +/* Define to 1 if the 'closedir' function returns void instead of 'int'. */ +/* #undef CLOSEDIR_VOID */ + +/* Define to one of '_getb67', 'GETB67', 'getb67' for Cray-2 and Cray-YMP + systems. This function is required for 'alloca.c' support on those systems. + */ +/* #undef CRAY_STACKSEG_END */ + +/* Define to 1 if using 'alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define to 1 if using 'getloadavg.c'. */ +#define C_GETLOADAVG 1 + +/* Define to 1 for DGUX with . */ +/* #undef DGUX */ + +/* Define to 1 if translation of program messages to the user's native + language is requested. */ +/* #undef ENABLE_NLS */ + +/* Use high resolution file timestamps if nonzero. */ +#define FILE_TIMESTAMP_HI_RES 0 + +/* Define to 1 if the 'getloadavg' function needs to be run setuid or setgid. + */ +/* #undef GETLOADAVG_PRIVILEGED */ + +/* Define to 1 if you have 'alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +/* #undef HAVE_ALLOCA_H */ + +/* Define to 1 if you have the 'atexit' function. */ +#define HAVE_ATEXIT 1 + +/* Use case insensitive file names */ +/* #undef HAVE_CASE_INSENSITIVE_FS */ + +/* Define to 1 if you have the clock_gettime function. */ +/* #undef HAVE_CLOCK_GETTIME */ + +/* Embed GNU Guile support. Windows build sets this on the + compilation command line. */ +/* #undef HAVE_GUILE */ + +/* Define if the GNU dcgettext() function is already present or preinstalled. + */ +/* #undef HAVE_DCGETTEXT */ + +/* Define to 1 if you have the declaration of 'bsd_signal', and to 0 if you + don't. */ +#define HAVE_DECL_BSD_SIGNAL 0 + +/* Define to 1 if you have the declaration of 'sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL_SYS_SIGLIST 0 + +/* Define to 1 if you have the declaration of '_sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL__SYS_SIGLIST 0 + +/* Define to 1 if you have the declaration of '__sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL___SYS_SIGLIST 0 + +/* Define to 1 if you have the header file, and it defines 'DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the header file, and it defines getcwd() + and chdir(). + */ +#if (defined(_MSC_VER) || defined(__BORLANDC__)) && !defined(__INTERIX) +# define HAVE_DIRECT_H 1 +#endif + +/* Use platform specific coding */ +#define HAVE_DOS_PATHS 1 + +/* Define to 1 if you have the 'dup2' function. */ +#define HAVE_DUP2 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the 'fdopen' function. */ +#ifdef __MINGW32__ +#define HAVE_FDOPEN 1 +#endif + +/* Define to 1 if you have the 'fileno' function. */ +#define HAVE_FILENO 1 + +/* Define to 1 if you have the 'getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the 'getgroups' function. */ +/* #undef HAVE_GETGROUPS */ + +/* Define to 1 if you have the 'gethostbyname' function. */ +/* #undef HAVE_GETHOSTBYNAME */ + +/* Define to 1 if you have the 'gethostname' function. */ +/* #undef HAVE_GETHOSTNAME */ + +/* Define to 1 if you have the 'getloadavg' function. */ +/* #undef HAVE_GETLOADAVG */ + +/* Define to 1 if you have the 'getrlimit' function. */ +/* #undef HAVE_GETRLIMIT */ + +/* Define if the GNU gettext() function is already present or preinstalled. */ +/* #undef HAVE_GETTEXT */ + +/* Define to 1 if you have a standard gettimeofday function */ +#ifdef __MINGW32__ +#define HAVE_GETTIMEOFDAY 1 +#endif + +/* Define if you have the iconv() function. */ +/* #undef HAVE_ICONV */ + +/* Define to 1 if you have the header file. */ +#ifdef __MINGW32__ +#define HAVE_INTTYPES_H 1 +#endif + +/* Define to 1 if you have the 'dgc' library (-ldgc). */ +/* #undef HAVE_LIBDGC */ + +/* Define to 1 if you have the 'kstat' library (-lkstat). */ +/* #undef HAVE_LIBKSTAT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +/*#define HAVE_LOCALE_H 1*/ + +/* Define to 1 if you have the 'lstat' function. */ +/* #undef HAVE_LSTAT */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACH_MACH_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the 'mkstemp' function. */ +/* #undef HAVE_MKSTEMP */ + +/* Define to 1 if you have the 'mktemp' function. */ +#define HAVE_MKTEMP 1 + +/* Define to 1 if you have the header file, and it defines 'DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NLIST_H */ + +/* Define to 1 if you have the 'pipe' function. */ +/* #undef HAVE_PIPE */ + +/* Define to 1 if you have the 'pstat_getdynamic' function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ + +/* Define to 1 if you have the 'readlink' function. */ +/* #undef HAVE_READLINK */ + +/* Define to 1 if you have the 'realpath' function. */ +/* #undef HAVE_REALPATH */ + +/* Define to 1 if defines the SA_RESTART constant. */ +/* #undef HAVE_SA_RESTART */ + +/* Define to 1 if you have the 'setegid' function. */ +/* #undef HAVE_SETEGID */ + +/* Define to 1 if you have the 'seteuid' function. */ +/* #undef HAVE_SETEUID */ + +/* Define to 1 if you have the 'setlinebuf' function. */ +/* #undef HAVE_SETLINEBUF */ + +/* Define to 1 if you have the 'setlocale' function. */ +/*#define HAVE_SETLOCALE 1*/ + +/* Define to 1 if you have the 'setregid' function. */ +/* #undef HAVE_SETREGID */ + +/* Define to 1 if you have the 'setreuid' function. */ +/* #undef HAVE_SETREUID */ + +/* Define to 1 if you have the 'setrlimit' function. */ +/* #undef HAVE_SETRLIMIT */ + +/* Define to 1 if you have the 'setvbuf' function. */ +#define HAVE_SETVBUF 1 + +/* Define to 1 if you have the 'sigaction' function. */ +/* #undef HAVE_SIGACTION */ + +/* Define to 1 if you have the 'sigsetmask' function. */ +/* #undef HAVE_SIGSETMASK */ + +/* Define to 1 if you have the 'socket' function. */ +/* #undef HAVE_SOCKET */ + +/* Define to 1 if you have the header file. */ +#ifdef __MINGW32__ +#define HAVE_STDINT_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the 'strcasecmp' function. */ +#ifdef __MINGW32__ +#define HAVE_STRCASECMP 1 +#endif + +/* Define to 1 if you have the 'strcmpi' function. */ +#define HAVE_STRCMPI 1 + +/* Define to 1 if you have the 'strcoll' function and it is properly defined. + */ +#define HAVE_STRCOLL 1 + +/* Define to 1 if you have the 'strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the 'strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the 'stricmp' function. */ +#define HAVE_STRICMP 1 + +/* Define to 1 if you have the header file. */ +/* #define HAVE_STRINGS_H 1 */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the 'strncasecmp' function. */ +#ifdef __MINGW32__ +#define HAVE_STRNCASECMP 1 +#endif + +/* Define to 1 if you have the 'strncmpi' function. */ +/* #undef HAVE_STRNCMPI */ + +/* Define to 1 if you have the 'strndup' function. */ +/* #undef HAVE_STRNDUP */ + +/* Define to 1 if you have the 'strnicmp' function. */ +#ifdef __MINGW32__ +#define HAVE_STRNICMP 1 +#endif + +/* Define to 1 if you have the 'strsignal' function. */ +/* #undef HAVE_STRSIGNAL */ + +/* Define to 1 if you have the `isatty' function. */ +#define HAVE_ISATTY 1 + +/* Define to 1 if you have the `ttyname' function. */ +#define HAVE_TTYNAME 1 +char *ttyname (int); + +/* Define to 1 if 'n_un.n_name' is a member of 'struct nlist'. */ +/* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ + +/* Define to 1 if you have the header file, and it defines 'DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file, and it defines 'DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#ifdef __MINGW32__ +#define HAVE_SYS_PARAM_H 1 +#endif + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_RESOURCE_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +#ifdef __MINGW32__ +#define HAVE_SYS_TIME_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_WAIT_H */ + +/* Define to 1 if you have the \'union wait' type in . */ +/* #undef HAVE_UNION_WAIT */ + +/* Define to 1 if you have the header file. */ +#ifdef __MINGW32__ +#define HAVE_UNISTD_H 1 +#endif + +/* Define to 1 if you have the 'wait3' function. */ +/* #undef HAVE_WAIT3 */ + +/* Define to 1 if you have the 'waitpid' function. */ +/* #undef HAVE_WAITPID */ + +/* Build host information. (not used by kmk) */ +#define MAKE_HOST "Windows32" + +/* Define to 1 to enable job server support in GNU make. */ +#define MAKE_JOBSERVER 1 + +/* Define to 1 to enable 'load' support in GNU make. */ +#define MAKE_LOAD 1 + +/* Define to 1 to enable symbolic link timestamp checking. */ +/* #undef MAKE_SYMLINKS */ + +/* Define to 1 if your 'struct nlist' has an 'n_un' member. Obsolete, depend + on 'HAVE_STRUCT_NLIST_N_UN_N_NAME */ +/* #undef NLIST_NAME_UNION */ + +/* Define to 1 if struct nlist.n_name is a pointer rather than an array. */ +/* #undef NLIST_STRUCT */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of this package (needed by automake) */ +#define PACKAGE "%PACKAGE%" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "bug-make@gnu.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "GNU make" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "http://www.gnu.org/software/make/" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "%VERSION%" + +/* Define to the character that separates directories in PATH. */ +#define PATH_SEPARATOR_CHAR ';' + +/* Define as the return type of signal handlers ('int' or 'void'). */ +#define RETSIGTYPE void + +/* Define to the name of the SCCS 'get' command. */ +#define SCCS_GET "echo no sccs get" + +/* Define this if the SCCS 'get' command understands the '-G' option. */ +/* #undef SCCS_GET_MINUS_G */ + +/* Define to 1 if the 'setvbuf' function takes the buffering type as its + second argument and the buffer pointer as the third, as on System V before + release 3. */ +/* #undef SETVBUF_REVERSED */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if the 'S_IS*' macros in do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if struct stat contains a nanoseconds field */ +/* #undef ST_MTIM_NSEC */ + +/* Define to 1 on System V Release 4. */ +/* #undef SVR4 */ + +/* Define to 1 if you can safely include both and . */ +#ifdef __MINGW32__ +#define TIME_WITH_SYS_TIME 1 +#endif + +/* Define to 1 for Encore UMAX. */ +/* #undef UMAX */ + +/* Define to 1 for Encore UMAX 4.3 that has instead of + . */ +/* #undef UMAX4_3 */ + +/* Version number of package */ +#define VERSION "%VERSION%" + +/* Define if using the dmalloc debugging malloc package */ +/* #undef WITH_DMALLOC */ + +/* Define to 1 if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +/* # undef _ALL_SOURCE */ +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to 1 if on MINIX. */ +/* #undef _MINIX */ + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to 1 if you need to in order for 'stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define to empty if 'const' does not conform to ANSI C. */ +/* #undef const */ + +#include + +/* Define to 'int' if doesn't define. */ +#define gid_t int + +/* Define to 'int' if does not define. */ +/* GCC 4.x reportedly defines pid_t. */ +#ifndef _PID_T_ +#ifdef _WIN64 +#define pid_t __int64 +#else +#define pid_t int +#endif +#endif + +/* Define to 'int' if doesn't define. */ +#define uid_t int + +/* Define uintmax_t if not defined in or . */ +#if !HAVE_STDINT_H && !HAVE_INTTYPES_H +#define uintmax_t unsigned long +#endif + +/* Define if you have that is POSIX.1 compatible. */ +/* #undef HAVE_SYS_WAIT_H */ + +/* Define to the installation directory for locales. */ +#define LOCALEDIR "" + +/* + * Refer to README.W32 for info on the following settings + */ + + +/* + * If you have a shell that does not grok 'sh -c quoted-command-line' + * correctly, you need this setting. Please see below for specific + * shell support. + */ +/*#define BATCH_MODE_ONLY_SHELL 1 */ + +/* + * Define if you have the Cygnus "Cygwin" GNU Windows32 tool set. + * Do NOT define BATCH_MODE_ONLY_SHELL if you define HAVE_CYGWIN_SHELL + */ +/*#define HAVE_CYGWIN_SHELL 1 */ + +/* + * Define if you have the MKS tool set or shell. Do NOT define + * BATCH_MODE_ONLY_SHELL if you define HAVE_MKS_SHELL + */ +/*#define HAVE_MKS_SHELL 1 */ + +/* + * Enforce the mutual exclusivity restriction. + */ +#ifdef HAVE_MKS_SHELL +#undef BATCH_MODE_ONLY_SHELL +#endif + +#ifdef HAVE_CYGWIN_SHELL +#undef BATCH_MODE_ONLY_SHELL +#endif diff --git a/src/kmk/config.h.darwin b/src/kmk/config.h.darwin new file mode 100644 index 0000000..18e2818 --- /dev/null +++ b/src/kmk/config.h.darwin @@ -0,0 +1,491 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if the `closedir' function returns void instead of `int'. */ +/* #undef CLOSEDIR_VOID */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +/* #undef CRAY_STACKSEG_END */ + +/* Define to 1 if using `alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define to 1 if using `getloadavg.c'. */ +/* #undef C_GETLOADAVG */ + +/* Define to 1 for DGUX with . */ +/* #undef DGUX */ + +/* Use high resolution file timestamps if nonzero. */ +#define FILE_TIMESTAMP_HI_RES 1 + +/* Define to 1 if the `getloadavg' function needs to be run setuid or setgid. + */ +/* #undef GETLOADAVG_PRIVILEGED */ + +/* Define to 1 if you have `alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#define HAVE_ALLOCA_H 1 + +/* Define to 1 if you have the `atexit' function. */ +#define HAVE_ATEXIT 1 + +/* Use case insensitive file names */ +/* #undef HAVE_CASE_INSENSITIVE_FS */ + +/* Define to 1 if you have the clock_gettime function. */ +#define HAVE_CLOCK_GETTIME 1 + +/* Define to 1 if you have the declaration of `bsd_signal', and to 0 if you + don't. */ +#define HAVE_DECL_BSD_SIGNAL 1 + +/* Define to 1 if you have the declaration of `dlerror', and to 0 if you + don't. */ +#define HAVE_DECL_DLERROR 1 + +/* Define to 1 if you have the declaration of `dlopen', and to 0 if you don't. + */ +#define HAVE_DECL_DLOPEN 1 + +/* Define to 1 if you have the declaration of `dlsym', and to 0 if you don't. + */ +#define HAVE_DECL_DLSYM 1 + +/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL_SYS_SIGLIST 1 + +/* Define to 1 if you have the declaration of `_sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL__SYS_SIGLIST 0 + +/* Define to 1 if you have the declaration of `__sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL___SYS_SIGLIST 0 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Use platform specific coding */ +/* #undef HAVE_DOS_PATHS */ + +/* Define to 1 if you have the `dup' function. */ +#define HAVE_DUP 1 + +/* Define to 1 if you have the `dup2' function. */ +#define HAVE_DUP2 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fdopen' function. */ +#define HAVE_FDOPEN 1 + +/* Define to 1 if you have the `fileno' function. */ +#define HAVE_FILENO 1 + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK 1 + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `getgroups' function. */ +#define HAVE_GETGROUPS 1 + +/* Define to 1 if you have the `gethostbyname' function. */ +/* #undef HAVE_GETHOSTBYNAME */ + +/* Define to 1 if you have the `gethostname' function. */ +/* #undef HAVE_GETHOSTNAME */ + +/* Define to 1 if you have the `getloadavg' function. */ +#define HAVE_GETLOADAVG 1 + +/* Define to 1 if you have the `getrlimit' function. */ +#define HAVE_GETRLIMIT 1 + +/* Define to 1 if you have a standard gettimeofday function */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `isatty' function. */ +#define HAVE_ISATTY 1 + +/* Define to 1 if you have the `dgc' library (-ldgc). */ +/* #undef HAVE_LIBDGC */ + +/* Define to 1 if you have the `kstat' library (-lkstat). */ +/* #undef HAVE_LIBKSTAT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `lstat' function. */ +#define HAVE_LSTAT 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACH_MACH_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mkstemp' function. */ +#define HAVE_MKSTEMP 1 + +/* Define to 1 if you have the `mktemp' function. */ +#define HAVE_MKTEMP 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NLIST_H */ + +/* Define to 1 if you have the `pipe' function. */ +#define HAVE_PIPE 1 + +#if 0 /* before 10.12.0 pselect is a useland implementation, which is insufficient for our purposes. */ +/* Define to 1 if you have the `pselect' function. */ +# define HAVE_PSELECT 1 +#else +# undef HAVE_PSELECT +#endif + +/* Define to 1 if you have the `pstat_getdynamic' function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ + +/* Define to 1 if you have the `readlink' function. */ +#define HAVE_READLINK 1 + +/* Define to 1 if you have the `realpath' function. */ +#define HAVE_REALPATH 1 + +/* Define to 1 if defines the SA_RESTART constant. */ +#define HAVE_SA_RESTART 1 + +/* Define to 1 if you have the `setegid' function. */ +#define HAVE_SETEGID 1 + +/* Define to 1 if you have the `seteuid' function. */ +#define HAVE_SETEUID 1 + +/* Define to 1 if you have the `setlinebuf' function. */ +#define HAVE_SETLINEBUF 1 + +/* Define to 1 if you have the `setlocale' function. */ +/* #undef HAVE_SETLOCALE */ + +/* Define to 1 if you have the `setregid' function. */ +#define HAVE_SETREGID 1 + +/* Define to 1 if you have the `setreuid' function. */ +#define HAVE_SETREUID 1 + +/* Define to 1 if you have the `setrlimit' function. */ +#define HAVE_SETRLIMIT 1 + +/* Define to 1 if you have the `setvbuf' function. */ +#define HAVE_SETVBUF 1 + +/* Define to 1 if you have the `sigaction' function. */ +#define HAVE_SIGACTION 1 + +/* Define to 1 if you have the `sigsetmask' function. */ +#define HAVE_SIGSETMASK 1 + +/* Define to 1 if you have the `socket' function. */ +/* #undef HAVE_SOCKET */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strcmpi' function. */ +/* #undef HAVE_STRCMPI */ + +/* Define to 1 if you have the `strcoll' function and it is properly defined. + */ +#define HAVE_STRCOLL 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `stricmp' function. */ +/* #undef HAVE_STRICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strncasecmp' function. */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the `strncmpi' function. */ +/* #undef HAVE_STRNCMPI */ + +/* Define to 1 if you have the `strndup' function. */ +/* #define HAVE_STRNDUP 1 - not in snow leopard */ + +/* Define to 1 if you have the `strnicmp' function. */ +/* #undef HAVE_STRNICMP */ + +/* Define to 1 if you have the `strsignal' function. */ +#define HAVE_STRSIGNAL 1 + +/* Define to 1 if `n_un.n_name' is a member of `struct nlist'. */ +/* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the `ttyname' function. */ +#define HAVE_TTYNAME 1 + +/* Define to 1 if the system has the type `uintmax_t'. */ +#define HAVE_UINTMAX_T 1 + +/* Define to 1 if you have the 'union wait' type in . */ +/* #undef HAVE_UNION_WAIT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if the system has the type `unsigned long long int'. */ +#define HAVE_UNSIGNED_LONG_LONG_INT 1 + +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VFORK_H */ + +/* Define to 1 if you have the `wait3' function. */ +#define HAVE_WAIT3 1 + +/* Define to 1 if you have the `waitpid' function. */ +#define HAVE_WAITPID 1 + +/* Define to 1 if `fork' works. */ +#define HAVE_WORKING_FORK 1 + +/* Define to 1 if `vfork' works. */ +#define HAVE_WORKING_VFORK 1 + +/* Build host information. */ +#define MAKE_HOST "x86_64-apple-darwin16.7.0" + +/* Define to 1 to enable job server support in GNU make. */ +#define MAKE_JOBSERVER 1 + +/* Define to 1 to enable 'load' support in GNU make. */ +/* #undef MAKE_LOAD */ + +/* Define to 1 to enable symbolic link timestamp checking. */ +#define MAKE_SYMLINKS 1 + +/* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend + on `HAVE_STRUCT_NLIST_N_UN_N_NAME */ +/* #undef NLIST_NAME_UNION */ + +/* Define to 1 if struct nlist.n_name is a pointer rather than an array. */ +/* #undef NLIST_STRUCT */ + +/* Name of package */ +#define PACKAGE "make" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "bug-make@gnu.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "GNU make" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "GNU make 4.2.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "make" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "http://www.gnu.org/software/make/" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "4.2.1" + +/* Define to the character that separates directories in PATH. */ +#define PATH_SEPARATOR_CHAR ':' + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to the name of the SCCS 'get' command. */ +#define SCCS_GET "get" + +/* Define to 1 if the SCCS 'get' command understands the '-G' option. */ +/* #undef SCCS_GET_MINUS_G */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if the `S_IS*' macros in do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if struct stat contains a nanoseconds field */ +#define ST_ATIM_NSEC st_atimespec.tv_nsec + +/* Define if struct stat contains a nanoseconds field */ +#define ST_MTIM_NSEC st_mtimespec.tv_nsec + +/* Define to 1 on System V Release 4. */ +/* #undef SVR4 */ + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 for Encore UMAX. */ +/* #undef UMAX */ + +/* Define to 1 for Encore UMAX 4.3 that has instead of + . */ +/* #undef UMAX4_3 */ + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif + + +/* Version number of package */ +#define VERSION "4.2.1" + +/* Use platform specific coding */ +/* #undef WINDOWS32 */ + +/* Define if using the dmalloc debugging malloc package */ +/* #undef WITH_DMALLOC */ + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to 1 if on MINIX. */ +/* #undef _MINIX */ + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define to `long int' if does not define. */ +/* #undef off_t */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to `int' if does not define. */ +/* #undef ssize_t */ + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define to the widest unsigned integer type if and + do not define. */ +/* #undef uintmax_t */ + +/* Define as `fork' if `vfork' does not work. */ +/* #undef vfork */ + +#include "inlined_memchr.h" diff --git a/src/kmk/config.h.freebsd b/src/kmk/config.h.freebsd new file mode 100644 index 0000000..8fa99cc --- /dev/null +++ b/src/kmk/config.h.freebsd @@ -0,0 +1,433 @@ +/* config.h. Generated by configure. */ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if the `closedir' function returns void instead of `int'. */ +/* #undef CLOSEDIR_VOID */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +/* #undef CRAY_STACKSEG_END */ + +/* Define to 1 if using `alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define to 1 if using `getloadavg.c'. */ +/* #undef C_GETLOADAVG */ + +/* Define to 1 for DGUX with . */ +/* #undef DGUX */ + +/* Use high resolution file timestamps if nonzero. */ +#define FILE_TIMESTAMP_HI_RES 0 + +/* Define to 1 if the `getloadavg' function needs to be run setuid or setgid. + */ +/* #undef GETLOADAVG_PRIVILEGED */ + +/* Define to 1 if you have `alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +/* #undef HAVE_ALLOCA_H */ + +/* Define to 1 if your compiler conforms to the ANSI C standard. */ +#define HAVE_ANSI_COMPILER 1 + +/* Define to 1 if you have the `atexit' function. */ +#define HAVE_ATEXIT 1 + +/* Define to 1 if you have the `bsd_signal' function. */ +/* #undef HAVE_BSD_SIGNAL */ + +/* Use case insensitive file names */ +/* #undef HAVE_CASE_INSENSITIVE_FS */ + +/* Define to 1 if you have the clock_gettime function. */ +/* #undef HAVE_CLOCK_GETTIME */ + +/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL_SYS_SIGLIST 1 + +/* Define to 1 if you have the declaration of `_sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL__SYS_SIGLIST 0 + +/* Define to 1 if you have the declaration of `__sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL___SYS_SIGLIST 0 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Use platform specific coding */ +/* #undef HAVE_DOS_PATHS */ + +/* Define to 1 if you have the `dup2' function. */ +#define HAVE_DUP2 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fdopen' function. */ +#define HAVE_FDOPEN 1 + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK 1 + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `getgroups' function. */ +#define HAVE_GETGROUPS 1 + +/* Define to 1 if you have the `gethostbyname' function. */ +/* #undef HAVE_GETHOSTBYNAME */ + +/* Define to 1 if you have the `gethostname' function. */ +/* #undef HAVE_GETHOSTNAME */ + +/* Define to 1 if you have the `getloadavg' function. */ +#define HAVE_GETLOADAVG 1 + +/* Define to 1 if you have the `getrlimit' function. */ +#define HAVE_GETRLIMIT 1 + +/* Define to 1 if you have a standard gettimeofday function */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `dgc' library (-ldgc). */ +/* #undef HAVE_LIBDGC */ + +/* Define to 1 if you have the `kstat' library (-lkstat). */ +/* #undef HAVE_LIBKSTAT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `lstat' function. */ +#define HAVE_LSTAT 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACH_MACH_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mkstemp' function. */ +#define HAVE_MKSTEMP 1 + +/* Define to 1 if you have the `mktemp' function. */ +#define HAVE_MKTEMP 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NLIST_H */ + +/* Define to 1 if you have the `pipe' function. */ +#define HAVE_PIPE 1 + +/* Define to 1 if you have the `pstat_getdynamic' function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ + +/* Define to 1 if you have the `readlink' function. */ +#define HAVE_READLINK 1 + +/* Define to 1 if you have the `realpath' function. */ +#define HAVE_REALPATH 1 + +/* Define to 1 if defines the SA_RESTART constant. */ +#define HAVE_SA_RESTART 1 + +/* Define to 1 if you have the `setegid' function. */ +#define HAVE_SETEGID 1 + +/* Define to 1 if you have the `seteuid' function. */ +#define HAVE_SETEUID 1 + +/* Define to 1 if you have the `setlinebuf' function. */ +#define HAVE_SETLINEBUF 1 + +/* Define to 1 if you have the `setlocale' function. */ +/* #undef HAVE_SETLOCALE */ + +/* Define to 1 if you have the `setregid' function. */ +#define HAVE_SETREGID 1 + +/* Define to 1 if you have the `setreuid' function. */ +#define HAVE_SETREUID 1 + +/* Define to 1 if you have the `setrlimit' function. */ +#define HAVE_SETRLIMIT 1 + +/* Define to 1 if you have the `setvbuf' function. */ +#define HAVE_SETVBUF 1 + +/* Define to 1 if you have the `sigaction' function. */ +#define HAVE_SIGACTION 1 + +/* Define to 1 if you have the `sigsetmask' function. */ +#define HAVE_SIGSETMASK 1 + +/* Define to 1 if you have the `socket' function. */ +/* #undef HAVE_SOCKET */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strcmpi' function. */ +/* #undef HAVE_STRCMPI */ + +/* Define to 1 if you have the `strcoll' function and it is properly defined. + */ +#define HAVE_STRCOLL 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `stricmp' function. */ +/* #undef HAVE_STRICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strsignal' function. */ +#define HAVE_STRSIGNAL 1 + +/* Define to 1 if `n_un.n_name' is member of `struct nlist'. */ +/* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the \`union wait' type in . */ +/* #undef HAVE_UNION_WAIT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VARARGS_H */ + +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VFORK_H */ + +/* Define to 1 if you have the `vprintf' function. */ +#define HAVE_VPRINTF 1 + +/* Define to 1 if you have the `wait3' function. */ +#define HAVE_WAIT3 1 + +/* Define to 1 if you have the `waitpid' function. */ +#define HAVE_WAITPID 1 + +/* Define to 1 if `fork' works. */ +#define HAVE_WORKING_FORK 1 + +/* Define to 1 if `vfork' works. */ +#define HAVE_WORKING_VFORK 1 + +/* Build host information. (not used by kmk) */ +#if defined(__X86__) || defined(__i386__) || defined(__I386__) +#define MAKE_HOST "i386-unknown-freebsd6.2" +#else +#define MAKE_HOST "amd64-unknown-freebsd6.2" +#endif + +/* Define to 1 to enable job server support in GNU make. */ +#define MAKE_JOBSERVER 1 + +/* Define to 1 to enable symbolic link timestamp checking. */ +#define MAKE_SYMLINKS 1 + +/* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend + on `HAVE_STRUCT_NLIST_N_UN_N_NAME */ +/* #undef NLIST_NAME_UNION */ + +/* Define to 1 if struct nlist.n_name is a pointer rather than an array. */ +/* #undef NLIST_STRUCT */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "make" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "bug-make@gnu.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "GNU make" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "GNU make 3.82" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "make" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "3.82" + +/* Define to the character that separates directories in PATH. */ +#define PATH_SEPARATOR_CHAR ':' + +/* Define to 1 if the C compiler supports function prototypes. */ +#define PROTOTYPES 1 + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to the name of the SCCS 'get' command. */ +#define SCCS_GET "get" + +/* Define to 1 if the SCCS 'get' command understands the '-G' option. */ +/* #undef SCCS_GET_MINUS_G */ + +/* Define to 1 if the `setvbuf' function takes the buffering type as its + second argument and the buffer pointer as the third, as on System V before + release 3. */ +/* #undef SETVBUF_REVERSED */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if the `S_IS*' macros in do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if struct stat contains a nanoseconds field */ +/* #undef ST_MTIM_NSEC */ + +/* Define to 1 on System V Release 4. */ +/* #undef SVR4 */ + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 for Encore UMAX. */ +/* #undef UMAX */ + +/* Define to 1 for Encore UMAX 4.3 that has instead of + . */ +/* #undef UMAX4_3 */ + +/* Version number of package */ +#define VERSION "3.82" + +/* Use platform specific coding */ +/* #undef WINDOWS32 */ + +/* Define if using the dmalloc debugging malloc package */ +/* #undef WITH_DMALLOC */ + +/* Define to 1 if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +/* # undef _ALL_SOURCE */ +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to 1 if on MINIX. */ +/* #undef _MINIX */ + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define like PROTOTYPES; this can be used by system headers. */ +#define __PROTOTYPES 1 + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define uintmax_t if not defined in or . */ +/* #undef uintmax_t */ + +/* Define as `fork' if `vfork' does not work. */ +/* #undef vfork */ + +#include "inlined_memchr.h" + diff --git a/src/kmk/config.h.haiku b/src/kmk/config.h.haiku new file mode 100644 index 0000000..3580374 --- /dev/null +++ b/src/kmk/config.h.haiku @@ -0,0 +1,459 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if the `closedir' function returns void instead of `int'. */ +/* #undef CLOSEDIR_VOID */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +/* #undef CRAY_STACKSEG_END */ + +/* Define to 1 if using `alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define to 1 if using `getloadavg.c'. */ +#define C_GETLOADAVG 1 + +/* Define to 1 for DGUX with . */ +/* #undef DGUX */ + +/* Use high resolution file timestamps if nonzero. */ +#define FILE_TIMESTAMP_HI_RES 1 + +/* Define to 1 if the `getloadavg' function needs to be run setuid or setgid. + */ +/* #undef GETLOADAVG_PRIVILEGED */ + +/* Define to 1 if you have `alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#define HAVE_ALLOCA_H 1 + +/* Define to 1 if your compiler conforms to the ANSI C standard. */ +#define HAVE_ANSI_COMPILER 1 + +/* Define to 1 if you have the `atexit' function. */ +#define HAVE_ATEXIT 1 + +/* Use case insensitive file names */ +/* #undef HAVE_CASE_INSENSITIVE_FS */ + +/* Define to 1 if you have the clock_gettime function. */ +#define HAVE_CLOCK_GETTIME 1 + +/* Define to 1 if you have the declaration of `bsd_signal', and to 0 if you + don't. */ +#define HAVE_DECL_BSD_SIGNAL 0 + +/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL_SYS_SIGLIST 1 + +/* Define to 1 if you have the declaration of `_sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL__SYS_SIGLIST 0 + +/* Define to 1 if you have the declaration of `__sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL___SYS_SIGLIST 0 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Use platform specific coding */ +/* #undef HAVE_DOS_PATHS */ + +/* Define to 1 if you have the `dup2' function. */ +#define HAVE_DUP2 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fdopen' function. */ +#define HAVE_FDOPEN 1 + +/* Define to 1 if you have the `fileno' function. */ +#define HAVE_FILENO 1 + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK 1 + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `getgroups' function. */ +#define HAVE_GETGROUPS 1 + +/* Define to 1 if you have the `gethostbyname' function. */ +/* #undef HAVE_GETHOSTBYNAME */ + +/* Define to 1 if you have the `gethostname' function. */ +/* #undef HAVE_GETHOSTNAME */ + +/* Define to 1 if you have the `getloadavg' function. */ +/* #undef HAVE_GETLOADAVG */ + +/* Define to 1 if you have the `getrlimit' function. */ +#define HAVE_GETRLIMIT 1 + +/* Define to 1 if you have a standard gettimeofday function */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `dgc' library (-ldgc). */ +/* #undef HAVE_LIBDGC */ + +/* Define to 1 if you have the `kstat' library (-lkstat). */ +/* #undef HAVE_LIBKSTAT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `lstat' function. */ +#define HAVE_LSTAT 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACH_MACH_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mkstemp' function. */ +#define HAVE_MKSTEMP 1 + +/* Define to 1 if you have the `mktemp' function. */ +#define HAVE_MKTEMP 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NLIST_H */ + +/* Define to 1 if you have the `pipe' function. */ +#define HAVE_PIPE 1 + +/* Define to 1 if you have the `pstat_getdynamic' function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ + +/* Define to 1 if you have the `readlink' function. */ +#define HAVE_READLINK 1 + +/* Define to 1 if you have the `realpath' function. */ +#define HAVE_REALPATH 1 + +/* Define to 1 if defines the SA_RESTART constant. */ +#define HAVE_SA_RESTART 1 + +/* Define to 1 if you have the `setegid' function. */ +#define HAVE_SETEGID 1 + +/* Define to 1 if you have the `seteuid' function. */ +#define HAVE_SETEUID 1 + +/* Define to 1 if you have the `setlinebuf' function. */ +#define HAVE_SETLINEBUF 1 + +/* Define to 1 if you have the `setlocale' function. */ +#define HAVE_SETLOCALE 1 + +/* Define to 1 if you have the `setregid' function. */ +#define HAVE_SETREGID 1 + +/* Define to 1 if you have the `setreuid' function. */ +#define HAVE_SETREUID 1 + +/* Define to 1 if you have the `setrlimit' function. */ +#define HAVE_SETRLIMIT 1 + +/* Define to 1 if you have the `setvbuf' function. */ +#define HAVE_SETVBUF 1 + +/* Define to 1 if you have the `sigaction' function. */ +#define HAVE_SIGACTION 1 + +/* Define to 1 if you have the `sigsetmask' function. */ +/* #undef HAVE_SIGSETMASK */ + +/* Define to 1 if you have the `socket' function. */ +/* #undef HAVE_SOCKET */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strcmpi' function. */ +/* #undef HAVE_STRCMPI */ + +/* Define to 1 if you have the `strcoll' function and it is properly defined. + */ +#define HAVE_STRCOLL 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `stricmp' function. */ +/* #undef HAVE_STRICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strncasecmp' function. */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the `strncmpi' function. */ +/* #undef HAVE_STRNCMPI */ + +/* Define to 1 if you have the `strndup' function. */ +#define HAVE_STRNDUP 1 + +/* Define to 1 if you have the `strnicmp' function. */ +/* #undef HAVE_STRNICMP */ + +/* Define to 1 if you have the `strsignal' function. */ +#define HAVE_STRSIGNAL 1 + +/* Define to 1 if `n_un.n_name' is a member of `struct nlist'. */ +/* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the \`union wait' type in . */ +/* #undef HAVE_UNION_WAIT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VARARGS_H */ + +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VFORK_H */ + +/* Define to 1 if you have the `vprintf' function. */ +#define HAVE_VPRINTF 1 + +/* Define to 1 if you have the `wait3' function. */ +/* #undef HAVE_WAIT3 */ + +/* Define to 1 if you have the `waitpid' function. */ +#define HAVE_WAITPID 1 + +/* Define to 1 if `fork' works. */ +#define HAVE_WORKING_FORK 1 + +/* Define to 1 if `vfork' works. */ +#define HAVE_WORKING_VFORK 1 + +/* Build host information. (not used by kmk) */ +#define MAKE_HOST "i586-pc-haiku" + +/* Define to 1 to enable job server support in GNU make. */ +#define MAKE_JOBSERVER 1 + +/* Define to 1 to enable symbolic link timestamp checking. */ +#define MAKE_SYMLINKS 1 + +/* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend + on `HAVE_STRUCT_NLIST_N_UN_N_NAME */ +/* #undef NLIST_NAME_UNION */ + +/* Define to 1 if struct nlist.n_name is a pointer rather than an array. */ +/* #undef NLIST_STRUCT */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "make" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "bug-make@gnu.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "GNU make" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "GNU make 3.82" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "make" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "http://www.gnu.org/software/make/" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "3.82" + +/* Define to the character that separates directories in PATH. */ +#define PATH_SEPARATOR_CHAR ':' + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to the name of the SCCS 'get' command. */ +#define SCCS_GET "get" + +/* Define to 1 if the SCCS 'get' command understands the '-G' option. */ +/* #undef SCCS_GET_MINUS_G */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if the `S_IS*' macros in do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if struct stat contains a nanoseconds field */ +#define ST_MTIM_NSEC tv_nsec + +/* Define to 1 on System V Release 4. */ +/* #undef SVR4 */ + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 for Encore UMAX. */ +/* #undef UMAX */ + +/* Define to 1 for Encore UMAX 4.3 that has instead of + . */ +/* #undef UMAX4_3 */ + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif + + +/* Version number of package */ +#define VERSION "3.82" + +/* Use platform specific coding */ +/* #undef WINDOWS32 */ + +/* Define if using the dmalloc debugging malloc package */ +/* #undef WITH_DMALLOC */ + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to 1 if on MINIX. */ +/* #undef _MINIX */ + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define uintmax_t if not defined in or . */ +/* #undef uintmax_t */ + +/* Define as `fork' if `vfork' does not work. */ +/* #undef vfork */ + +#include "inlined_memchr.h" diff --git a/src/kmk/config.h.linux b/src/kmk/config.h.linux new file mode 100644 index 0000000..99c5fa4 --- /dev/null +++ b/src/kmk/config.h.linux @@ -0,0 +1,498 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* + * bird: Move up this bunch so we can include features.h early. + */ + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif + +#include /* bird */ + + +/* Define to 1 if the `closedir' function returns void instead of `int'. */ +/* #undef CLOSEDIR_VOID */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +/* #undef CRAY_STACKSEG_END */ + +/* Define to 1 if using `alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define to 1 if using `getloadavg.c'. */ +/* #undef C_GETLOADAVG */ + +/* Define to 1 for DGUX with . */ +/* #undef DGUX */ + +/* Use high resolution file timestamps if nonzero. */ +#define FILE_TIMESTAMP_HI_RES 1 + +/* Define to 1 if the `getloadavg' function needs to be run setuid or setgid. + */ +/* #undef GETLOADAVG_PRIVILEGED */ + +/* Define to 1 if you have `alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#define HAVE_ALLOCA_H 1 + +/* Define to 1 if you have the `atexit' function. */ +#define HAVE_ATEXIT 1 + +/* Use case insensitive file names */ +/* #undef HAVE_CASE_INSENSITIVE_FS */ + +/* Define to 1 if you have the clock_gettime function. */ +#define HAVE_CLOCK_GETTIME 1 + +/* Define to 1 if you have the declaration of `bsd_signal', and to 0 if you + don't. */ +/* #define HAVE_DECL_BSD_SIGNAL 1 */ + +/* Define to 1 if you have the declaration of `dlerror', and to 0 if you + don't. */ +#define HAVE_DECL_DLERROR 1 + +/* Define to 1 if you have the declaration of `dlopen', and to 0 if you don't. + */ +#define HAVE_DECL_DLOPEN 1 + +/* Define to 1 if you have the declaration of `dlsym', and to 0 if you don't. + */ +#define HAVE_DECL_DLSYM 1 + +/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL_SYS_SIGLIST 1 + +/* Define to 1 if you have the declaration of `_sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL__SYS_SIGLIST 1 + +/* Define to 1 if you have the declaration of `__sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL___SYS_SIGLIST 0 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Use platform specific coding */ +/* #undef HAVE_DOS_PATHS */ + +/* Define to 1 if you have the `dup' function. */ +#define HAVE_DUP 1 + +/* Define to 1 if you have the `dup2' function. */ +#define HAVE_DUP2 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fdopen' function. */ +#define HAVE_FDOPEN 1 + +/* Define to 1 if you have the `fileno' function. */ +#define HAVE_FILENO 1 + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK 1 + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `getgroups' function. */ +#define HAVE_GETGROUPS 1 + +/* Define to 1 if you have the `gethostbyname' function. */ +/* #undef HAVE_GETHOSTBYNAME */ + +/* Define to 1 if you have the `gethostname' function. */ +/* #undef HAVE_GETHOSTNAME */ + +/* Define to 1 if you have the `getloadavg' function. */ +#define HAVE_GETLOADAVG 1 + +/* Define to 1 if you have the `getrlimit' function. */ +#define HAVE_GETRLIMIT 1 + +/* Define to 1 if you have a standard gettimeofday function */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `isatty' function. */ +#define HAVE_ISATTY 1 + +/* Define to 1 if you have the `dgc' library (-ldgc). */ +/* #undef HAVE_LIBDGC */ + +/* Define to 1 if you have the `kstat' library (-lkstat). */ +/* #undef HAVE_LIBKSTAT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `lstat' function. */ +#define HAVE_LSTAT 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACH_MACH_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mkstemp' function. */ +#define HAVE_MKSTEMP 1 + +/* Define to 1 if you have the `mktemp' function. */ +#define HAVE_MKTEMP 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NLIST_H */ + +/* Define to 1 if you have the `pipe' function. */ +#define HAVE_PIPE 1 + +/* Define to 1 if you have the `pselect' function. */ +#define HAVE_PSELECT 1 + +/* Define to 1 if you have the `pstat_getdynamic' function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ + +/* Define to 1 if you have the `readlink' function. */ +#define HAVE_READLINK 1 + +/* Define to 1 if you have the `realpath' function. */ +#define HAVE_REALPATH 1 + +/* Define to 1 if defines the SA_RESTART constant. */ +#define HAVE_SA_RESTART 1 + +/* Define to 1 if you have the `setegid' function. */ +#define HAVE_SETEGID 1 + +/* Define to 1 if you have the `seteuid' function. */ +#define HAVE_SETEUID 1 + +/* Define to 1 if you have the `setlinebuf' function. */ +#define HAVE_SETLINEBUF 1 + +/* Define to 1 if you have the `setlocale' function. */ +/* #undef HAVE_SETLOCALE */ + +/* Define to 1 if you have the `setregid' function. */ +#define HAVE_SETREGID 1 + +/* Define to 1 if you have the `setreuid' function. */ +#define HAVE_SETREUID 1 + +/* Define to 1 if you have the `setrlimit' function. */ +#define HAVE_SETRLIMIT 1 + +/* Define to 1 if you have the `setvbuf' function. */ +#define HAVE_SETVBUF 1 + +/* Define to 1 if you have the `sigaction' function. */ +#define HAVE_SIGACTION 1 + +/* Define to 1 if you have the `sigsetmask' function. */ +#define HAVE_SIGSETMASK 1 + +/* Define to 1 if you have the `socket' function. */ +/* #undef HAVE_SOCKET */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strcmpi' function. */ +/* #undef HAVE_STRCMPI */ + +/* Define to 1 if you have the `strcoll' function and it is properly defined. + */ +#define HAVE_STRCOLL 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `stricmp' function. */ +/* #undef HAVE_STRICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strncasecmp' function. */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the `strncmpi' function. */ +/* #undef HAVE_STRNCMPI */ + +/* Define to 1 if you have the `strndup' function. */ +#define HAVE_STRNDUP 1 + +/* Define to 1 if you have the `strnicmp' function. */ +/* #undef HAVE_STRNICMP */ + +/* Define to 1 if you have the `strsignal' function. */ +#define HAVE_STRSIGNAL 1 + +/* Define to 1 if `n_un.n_name' is a member of `struct nlist'. */ +/* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the `ttyname' function. */ +#define HAVE_TTYNAME 1 + +/* Define to 1 if the system has the type `uintmax_t'. */ +#define HAVE_UINTMAX_T 1 + +/* Define to 1 if you have the 'union wait' type in . */ +/* #undef HAVE_UNION_WAIT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if the system has the type `unsigned long long int'. */ +#define HAVE_UNSIGNED_LONG_LONG_INT 1 + +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VFORK_H */ + +/* Define to 1 if you have the `wait3' function. */ +#define HAVE_WAIT3 1 + +/* Define to 1 if you have the `waitpid' function. */ +#define HAVE_WAITPID 1 + +/* Define to 1 if `fork' works. */ +#define HAVE_WORKING_FORK 1 + +/* Define to 1 if `vfork' works. */ +#define HAVE_WORKING_VFORK 1 + +/* Build host information. (not used by kmk) */ +#define MAKE_HOST "i686-pc-linux-gnu" + +/* Define to 1 to enable job server support in GNU make. */ +#define MAKE_JOBSERVER 1 + +/* Define to 1 to enable 'load' support in GNU make. */ +/* #undef MAKE_LOAD */ + +/* Define to 1 to enable symbolic link timestamp checking. */ +#define MAKE_SYMLINKS 1 + +/* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend + on `HAVE_STRUCT_NLIST_N_UN_N_NAME */ +/* #undef NLIST_NAME_UNION */ + +/* Define to 1 if struct nlist.n_name is a pointer rather than an array. */ +/* #undef NLIST_STRUCT */ + +/* Name of package */ +#define PACKAGE "make" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "bug-make@gnu.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "GNU make" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "GNU make 4.2.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "make" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "http://kbuild.org/" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "4.2.1" + +/* Define to the character that separates directories in PATH. */ +#define PATH_SEPARATOR_CHAR ':' + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to the name of the SCCS 'get' command. */ +#define SCCS_GET "get" + +/* Define to 1 if the SCCS 'get' command understands the '-G' option. */ +/* #undef SCCS_GET_MINUS_G */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if the `S_IS*' macros in do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if struct stat contains a nanoseconds field */ +#if defined(__USE_XOPEN2K8) || defined(__USE_MISC) +# define ST_MTIM_NSEC st_mtim.tv_nsec +# define ST_ATIM_NSEC st_atim.tv_nsec +#else +# define ST_MTIM_NSEC st_mtimensec +# define ST_ATIM_NSEC st_atimensec +#endif + +/* Define to 1 on System V Release 4. */ +/* #undef SVR4 */ + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 for Encore UMAX. */ +/* #undef UMAX */ + +/* Define to 1 for Encore UMAX 4.3 that has instead of + . */ +/* #undef UMAX4_3 */ + + +/* Version number of package */ +#define VERSION "4.2.1" + +/* Use platform specific coding */ +/* #undef WINDOWS32 */ + +/* Define if using the dmalloc debugging malloc package */ +/* #undef WITH_DMALLOC */ + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#define _FILE_OFFSET_BITS 64 + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to 1 if on MINIX. */ +/* #undef _MINIX */ + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define to `long int' if does not define. */ +/* #undef off_t */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to `int' if does not define. */ +/* #undef ssize_t */ + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define to the widest unsigned integer type if and + do not define. */ +/* #undef uintmax_t */ + +/* Define as `fork' if `vfork' does not work. */ +/* #undef vfork */ + +#include "inlined_memchr.h" + diff --git a/src/kmk/config.h.netbsd b/src/kmk/config.h.netbsd new file mode 100755 index 0000000..77c43d1 --- /dev/null +++ b/src/kmk/config.h.netbsd @@ -0,0 +1,459 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if the `closedir' function returns void instead of `int'. */ +/* #undef CLOSEDIR_VOID */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +/* #undef CRAY_STACKSEG_END */ + +/* Define to 1 if using `alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define to 1 if using `getloadavg.c'. */ +/* #undef C_GETLOADAVG */ + +/* Define to 1 for DGUX with . */ +/* #undef DGUX */ + +/* Use high resolution file timestamps if nonzero. */ +#define FILE_TIMESTAMP_HI_RES 0 + +/* Define to 1 if the `getloadavg' function needs to be run setuid or setgid. + */ +/* #undef GETLOADAVG_PRIVILEGED */ + +/* Define to 1 if you have `alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +/* #undef HAVE_ALLOCA_H */ + +/* Define to 1 if your compiler conforms to the ANSI C standard. */ +#define HAVE_ANSI_COMPILER 1 + +/* Define to 1 if you have the `atexit' function. */ +#define HAVE_ATEXIT 1 + +/* Use case insensitive file names */ +/* #undef HAVE_CASE_INSENSITIVE_FS */ + +/* Define to 1 if you have the clock_gettime function. */ +/* #undef HAVE_CLOCK_GETTIME */ + +/* Define to 1 if you have the declaration of `bsd_signal', and to 0 if you + don't. */ +#define HAVE_DECL_BSD_SIGNAL 0 + +/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL_SYS_SIGLIST 1 + +/* Define to 1 if you have the declaration of `_sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL__SYS_SIGLIST 0 + +/* Define to 1 if you have the declaration of `__sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL___SYS_SIGLIST 0 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Use platform specific coding */ +/* #undef HAVE_DOS_PATHS */ + +/* Define to 1 if you have the `dup2' function. */ +#define HAVE_DUP2 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fdopen' function. */ +#define HAVE_FDOPEN 1 + +/* Define to 1 if you have the `fileno' function. */ +#define HAVE_FILENO 1 + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK 1 + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `getgroups' function. */ +#define HAVE_GETGROUPS 1 + +/* Define to 1 if you have the `gethostbyname' function. */ +/* #undef HAVE_GETHOSTBYNAME */ + +/* Define to 1 if you have the `gethostname' function. */ +/* #undef HAVE_GETHOSTNAME */ + +/* Define to 1 if you have the `getloadavg' function. */ +#define HAVE_GETLOADAVG 1 + +/* Define to 1 if you have the `getrlimit' function. */ +#define HAVE_GETRLIMIT 1 + +/* Define to 1 if you have a standard gettimeofday function */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `dgc' library (-ldgc). */ +/* #undef HAVE_LIBDGC */ + +/* Define to 1 if you have the `kstat' library (-lkstat). */ +/* #undef HAVE_LIBKSTAT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `lstat' function. */ +#define HAVE_LSTAT 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACH_MACH_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mkstemp' function. */ +#define HAVE_MKSTEMP 1 + +/* Define to 1 if you have the `mktemp' function. */ +#define HAVE_MKTEMP 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NLIST_H */ + +/* Define to 1 if you have the `pipe' function. */ +#define HAVE_PIPE 1 + +/* Define to 1 if you have the `pstat_getdynamic' function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ + +/* Define to 1 if you have the `readlink' function. */ +#define HAVE_READLINK 1 + +/* Define to 1 if you have the `realpath' function. */ +#define HAVE_REALPATH 1 + +/* Define to 1 if defines the SA_RESTART constant. */ +#define HAVE_SA_RESTART 1 + +/* Define to 1 if you have the `setegid' function. */ +#define HAVE_SETEGID 1 + +/* Define to 1 if you have the `seteuid' function. */ +#define HAVE_SETEUID 1 + +/* Define to 1 if you have the `setlinebuf' function. */ +#define HAVE_SETLINEBUF 1 + +/* Define to 1 if you have the `setlocale' function. */ +/* #undef HAVE_SETLOCALE */ + +/* Define to 1 if you have the `setregid' function. */ +#define HAVE_SETREGID 1 + +/* Define to 1 if you have the `setreuid' function. */ +#define HAVE_SETREUID 1 + +/* Define to 1 if you have the `setrlimit' function. */ +#define HAVE_SETRLIMIT 1 + +/* Define to 1 if you have the `setvbuf' function. */ +#define HAVE_SETVBUF 1 + +/* Define to 1 if you have the `sigaction' function. */ +#define HAVE_SIGACTION 1 + +/* Define to 1 if you have the `sigsetmask' function. */ +#define HAVE_SIGSETMASK 1 + +/* Define to 1 if you have the `socket' function. */ +/* #undef HAVE_SOCKET */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strcmpi' function. */ +/* #undef HAVE_STRCMPI */ + +/* Define to 1 if you have the `strcoll' function and it is properly defined. + */ +#define HAVE_STRCOLL 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `stricmp' function. */ +/* #undef HAVE_STRICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strncasecmp' function. */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the `strncmpi' function. */ +/* #undef HAVE_STRNCMPI */ + +/* Define to 1 if you have the `strndup' function. */ +#define HAVE_STRNDUP 1 + +/* Define to 1 if you have the `strnicmp' function. */ +/* #undef HAVE_STRNICMP */ + +/* Define to 1 if you have the `strsignal' function. */ +#define HAVE_STRSIGNAL 1 + +/* Define to 1 if `n_un.n_name' is a member of `struct nlist'. */ +/* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the \`union wait' type in . */ +/* #undef HAVE_UNION_WAIT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VARARGS_H */ + +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VFORK_H */ + +/* Define to 1 if you have the `vprintf' function. */ +#define HAVE_VPRINTF 1 + +/* Define to 1 if you have the `wait3' function. */ +#define HAVE_WAIT3 1 + +/* Define to 1 if you have the `waitpid' function. */ +#define HAVE_WAITPID 1 + +/* Define to 1 if `fork' works. */ +#define HAVE_WORKING_FORK 1 + +/* Define to 1 if `vfork' works. */ +#define HAVE_WORKING_VFORK 1 + +/* Build host information. (not used by kmk) */ +#define MAKE_HOST "i386-unknown-netbsdelf5.1." + +/* Define to 1 to enable job server support in GNU make. */ +#define MAKE_JOBSERVER 1 + +/* Define to 1 to enable symbolic link timestamp checking. */ +#define MAKE_SYMLINKS 1 + +/* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend + on `HAVE_STRUCT_NLIST_N_UN_N_NAME */ +/* #undef NLIST_NAME_UNION */ + +/* Define to 1 if struct nlist.n_name is a pointer rather than an array. */ +/* #undef NLIST_STRUCT */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "make" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "bug-make@gnu.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "GNU make" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "GNU make 3.82" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "make" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "http://www.gnu.org/software/make/" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "3.82" + +/* Define to the character that separates directories in PATH. */ +#define PATH_SEPARATOR_CHAR ':' + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to the name of the SCCS 'get' command. */ +#define SCCS_GET "get" + +/* Define to 1 if the SCCS 'get' command understands the '-G' option. */ +/* #undef SCCS_GET_MINUS_G */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if the `S_IS*' macros in do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if struct stat contains a nanoseconds field */ +/* #undef ST_MTIM_NSEC */ + +/* Define to 1 on System V Release 4. */ +/* #undef SVR4 */ + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 for Encore UMAX. */ +/* #undef UMAX */ + +/* Define to 1 for Encore UMAX 4.3 that has instead of + . */ +/* #undef UMAX4_3 */ + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif + + +/* Version number of package */ +#define VERSION "3.82" + +/* Use platform specific coding */ +/* #undef WINDOWS32 */ + +/* Define if using the dmalloc debugging malloc package */ +/* #undef WITH_DMALLOC */ + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to 1 if on MINIX. */ +/* #undef _MINIX */ + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define uintmax_t if not defined in or . */ +/* #undef uintmax_t */ + +/* Define as `fork' if `vfork' does not work. */ +/* #undef vfork */ + +#include "inlined_memchr.h" diff --git a/src/kmk/config.h.os2 b/src/kmk/config.h.os2 new file mode 100644 index 0000000..32b919c --- /dev/null +++ b/src/kmk/config.h.os2 @@ -0,0 +1,476 @@ +/* config.h. Generated by configure. */ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if the `closedir' function returns void instead of `int'. */ +/* #undef CLOSEDIR_VOID */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +/* #undef CRAY_STACKSEG_END */ + +/* Define to 1 if using `alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define to 1 if using `getloadavg.c'. */ +/* #undef C_GETLOADAVG */ + +/* Define to 1 for DGUX with . */ +/* #undef DGUX */ + +/* Define to 1 if translation of program messages to the user's native + language is requested. */ +#define ENABLE_NLS 1 + +/* Use high resolution file timestamps if nonzero. */ +#define FILE_TIMESTAMP_HI_RES 0 + +/* Define to 1 if the `getloadavg' function needs to be run setuid or setgid. + */ +/* #undef GETLOADAVG_PRIVILEGED */ + +/* Define to 1 if you have `alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#define HAVE_ALLOCA_H 1 + +/* Define if your compiler conforms to the ANSI C standard. */ +#define HAVE_ANSI_COMPILER 1 + +/* Define to 1 if you have the `atexit' function. */ +#define HAVE_ATEXIT 1 + +/* Use case insensitive file names */ +/* #undef HAVE_CASE_INSENSITIVE_FS */ + +/* Define to 1 if you have the declaration of `bsd_signal', and to 0 if you + don't. */ +#define HAVE_DECL_BSD_SIGNAL 1 + +/* Define if you have the clock_gettime function. */ +/* #undef HAVE_CLOCK_GETTIME */ + +/* Define if the GNU dcgettext() function is already present or preinstalled. + */ +#define HAVE_DCGETTEXT 1 + +/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL_SYS_SIGLIST 1 + +/* Define to 1 if you have the declaration of `_sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL__SYS_SIGLIST 0 + +/* Define to 1 if you have the declaration of `__sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL___SYS_SIGLIST 0 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Use platform specific coding */ +#define HAVE_DOS_PATHS 1 + +/* Define to 1 if you have the `dup2' function. */ +#define HAVE_DUP2 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fdopen' function. */ +#define HAVE_FDOPEN 1 + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK 1 + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `getgroups' function. */ +#define HAVE_GETGROUPS 1 + +/* Define to 1 if you have the `gethostbyname' function. */ +/* #undef HAVE_GETHOSTBYNAME */ + +/* Define to 1 if you have the `gethostname' function. */ +/* #undef HAVE_GETHOSTNAME */ + +/* Define to 1 if you have the `getloadavg' function. */ +#define HAVE_GETLOADAVG 1 + +/* Define to 1 if you have the `getrlimit' function. */ +#define HAVE_GETRLIMIT 1 + +/* Define if the GNU gettext() function is already present or preinstalled. */ +#define HAVE_GETTEXT 1 + +/* Define if you have a standard gettimeofday function */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define if you have the iconv() function. */ +/* #undef HAVE_ICONV */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `dgc' library (-ldgc). */ +/* #undef HAVE_LIBDGC */ + +/* Define to 1 if you have the `kstat' library (-lkstat). */ +/* #undef HAVE_LIBKSTAT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `lstat' function. */ +#define HAVE_LSTAT 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACH_MACH_H */ + +/* Define to 1 if you have the `memcpy' function. */ +#define HAVE_MEMCPY 1 + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mkstemp' function. */ +#define HAVE_MKSTEMP 1 + +/* Define to 1 if you have the `mktemp' function. */ +#define HAVE_MKTEMP 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NLIST_H */ + +/* Define to 1 if you have the `pipe' function. */ +#define HAVE_PIPE 1 + +/* Define to 1 if you have the `pstat_getdynamic' function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ + +/* Define to 1 if you have the `readlink' function. */ +#define HAVE_READLINK 1 + +/* Define to 1 if you have the `realpath' function. */ +#define HAVE_REALPATH 1 + +/* Define if defines the SA_RESTART constant. */ +#define HAVE_SA_RESTART 1 + +/* Define to 1 if you have the `setegid' function. */ +#define HAVE_SETEGID 1 + +/* Define to 1 if you have the `seteuid' function. */ +#define HAVE_SETEUID 1 + +/* Define to 1 if you have the `setlinebuf' function. */ +#define HAVE_SETLINEBUF 1 + +/* Define to 1 if you have the `setlocale' function. */ +/* #undef HAVE_SETLOCALE */ + +/* Define to 1 if you have the `setregid' function. */ +#define HAVE_SETREGID 1 + +/* Define to 1 if you have the `setreuid' function. */ +#define HAVE_SETREUID 1 + +/* Define to 1 if you have the `setrlimit' function. */ +#define HAVE_SETRLIMIT 1 + +/* Define to 1 if you have the `setvbuf' function. */ +#define HAVE_SETVBUF 1 + +/* Define to 1 if you have the `sigaction' function. */ +#define HAVE_SIGACTION 1 + +/* Define to 1 if you have the `sigsetmask' function. */ +#define HAVE_SIGSETMASK 1 + +/* Define to 1 if you have the `socket' function. */ +/* #undef HAVE_SOCKET */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +/* #undef HAVE_STRCASECMP */ + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strcoll' function and it is properly defined. + */ +#define HAVE_STRCOLL 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strncasecmp' function. */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the `strncmpi' function. */ +/* #undef HAVE_STRNCMPI */ + +/* Define to 1 if you have the `strsignal' function. */ +#define HAVE_STRSIGNAL 1 + +/* Define to 1 if you have the `strndup' function. */ +#define HAVE_STRNDUP 1 + +/* Define to 1 if you have the `strnicmp' function. */ +#define HAVE_STRNICMP 1 + +/* Define to 1 if `n_un.n_name' is member of `struct nlist'. */ +/* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define this if you have the \`union wait' type in . */ +/* #undef HAVE_UNION_WAIT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VARARGS_H */ + +/* Define to 1 if you have the `vfork' function. */ +/* #undef HAVE_VFORK */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VFORK_H */ + +/* Define to 1 if you have the `vprintf' function. */ +#define HAVE_VPRINTF 1 + +/* Define to 1 if you have the `wait3' function. */ +#define HAVE_WAIT3 1 + +/* Define to 1 if you have the `waitpid' function. */ +#define HAVE_WAITPID 1 + +/* Define to 1 if `fork' works. */ +#define HAVE_WORKING_FORK 1 + +/* Define to 1 if `vfork' works. */ +/* #undef HAVE_WORKING_VFORK */ + +/* Build host information. (not used by kmk) */ +#define MAKE_HOST "i386-pc-os2-emx" + +/* Define this to enable job server support in GNU make. */ +#define MAKE_JOBSERVER 1 + +/* Define this to enable symbolic link timestamp checking. */ +#define MAKE_SYMLINKS 1 + +/* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend + on `HAVE_STRUCT_NLIST_N_UN_N_NAME */ +/* #undef NLIST_NAME_UNION */ + +/* Define if struct nlist.n_name is a pointer rather than an array. */ +/* #undef NLIST_STRUCT */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "make" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "bug-make@gnu.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "GNU make" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "GNU make 3.82" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "make" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "3.82" + +/* Define to 1 if the C compiler supports function prototypes. */ +#define PROTOTYPES 1 + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to the name of the SCCS 'get' command. */ +#define SCCS_GET "get" + +/* Define this if the SCCS 'get' command understands the '-G' option. */ +/* #undef SCCS_GET_MINUS_G */ + +/* Define to 1 if the `setvbuf' function takes the buffering type as its + second argument and the buffer pointer as the third, as on System V before + release 3. */ +/* #undef SETVBUF_REVERSED */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if the `S_IS*' macros in do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if struct stat contains a nanoseconds field */ +/* #undef ST_MTIM_NSEC */ + +/* Define to 1 on System V Release 4. */ +/* #undef SVR4 */ + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 for Encore UMAX. */ +/* #undef UMAX */ + +/* Define to 1 for Encore UMAX 4.3 that has instead of + . */ +/* #undef UMAX4_3 */ + +/* Version number of package */ +#define VERSION "3.81" + +/* Use platform specific coding */ +/* #undef WINDOWS32 */ + +/* Define if using the dmalloc debugging malloc package */ +/* #undef WITH_DMALLOC */ + +/* Define to 1 if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +/* # undef _ALL_SOURCE */ +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to 1 if on MINIX. */ +/* #undef _MINIX */ + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define like PROTOTYPES; this can be used by system headers. */ +#define __PROTOTYPES 1 + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define uintmax_t if not defined in or . */ +/* #undef uintmax_t */ + +/* Define as `fork' if `vfork' does not work. */ +#define vfork fork + +/* + * Modifications: + */ + +/* Define to the installation directory for locales. */ +#define LOCALEDIR "" + +/* + * If you have a shell that does not grok 'sh -c quoted-command-line' + * correctly, you need this setting. Please see below for specific + * shell support. + */ +#define BATCH_MODE_ONLY_SHELL 1 + +#define _DIRENT_HAVE_D_NAMLEN 1 +#define _DIRENT_HAVE_D_TYPE 1 + +#define INCLUDEDIR "." +#define LIBDIR "." + +#include "inlined_memchr.h" + diff --git a/src/kmk/config.h.solaris b/src/kmk/config.h.solaris new file mode 100644 index 0000000..adeaca3 --- /dev/null +++ b/src/kmk/config.h.solaris @@ -0,0 +1,443 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if the `closedir' function returns void instead of `int'. */ +/* #undef CLOSEDIR_VOID */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +/* #undef CRAY_STACKSEG_END */ + +/* Define to 1 if using `alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define to 1 if using `getloadavg.c'. */ +/* #undef C_GETLOADAVG */ + +/* Define to 1 for DGUX with . */ +/* #undef DGUX */ + +/* Use high resolution file timestamps if nonzero. */ +#define FILE_TIMESTAMP_HI_RES 1 + +/* Define to 1 if the `getloadavg' function needs to be run setuid or setgid. + */ +/* #undef GETLOADAVG_PRIVILEGED */ + +/* Define to 1 if you have `alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#define HAVE_ALLOCA_H 1 + +/* Define to 1 if your compiler conforms to the ANSI C standard. */ +#define HAVE_ANSI_COMPILER 1 + +/* Define to 1 if you have the `atexit' function. */ +#define HAVE_ATEXIT 1 + +/* Define to 1 if you have the `bsd_signal' function. */ +#define HAVE_BSD_SIGNAL 1 +#define HAVE_DECL_BSD_SIGNAL 1 + +/* Use case insensitive file names */ +/* #undef HAVE_CASE_INSENSITIVE_FS */ + +/* Define to 1 if you have the clock_gettime function. */ +#define HAVE_CLOCK_GETTIME 1 + +/* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL_SYS_SIGLIST 0 + +/* Define to 1 if you have the declaration of `_sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL__SYS_SIGLIST 1 + +/* Define to 1 if you have the declaration of `__sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL___SYS_SIGLIST 0 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#define HAVE_DOPRNT 1 + +/* Use platform specific coding */ +/* #undef HAVE_DOS_PATHS */ + +/* Define to 1 if you have the `dup2' function. */ +#define HAVE_DUP2 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fdopen' function. */ +#define HAVE_FDOPEN 1 + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK 1 + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `getgroups' function. */ +#define HAVE_GETGROUPS 1 + +/* Define to 1 if you have the `gethostbyname' function. */ +/* #undef HAVE_GETHOSTBYNAME */ + +/* Define to 1 if you have the `gethostname' function. */ +/* #undef HAVE_GETHOSTNAME */ + +/* Define to 1 if you have the `getloadavg' function. */ +#define HAVE_GETLOADAVG 1 + +/* Define to 1 if you have the `getrlimit' function. */ +#define HAVE_GETRLIMIT 1 + +/* Define to 1 if you have a standard gettimeofday function */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `dgc' library (-ldgc). */ +/* #undef HAVE_LIBDGC */ + +/* Define to 1 if you have the `kstat' library (-lkstat). */ +#define HAVE_LIBKSTAT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `lstat' function. */ +#define HAVE_LSTAT 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACH_MACH_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mkstemp' function. */ +#define HAVE_MKSTEMP 1 + +/* Define to 1 if you have the `mktemp' function. */ +#define HAVE_MKTEMP 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NLIST_H */ + +/* Define to 1 if you have the `pipe' function. */ +#define HAVE_PIPE 1 + +/* Define to 1 if you have the `pselect' function. */ +#define HAVE_PSELECT 1 + +/* Define to 1 if you have the `pstat_getdynamic' function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ + +/* Define to 1 if you have the `readlink' function. */ +#define HAVE_READLINK 1 + +/* Define to 1 if you have the `realpath' function. */ +#define HAVE_REALPATH 1 + +/* Define to 1 if defines the SA_RESTART constant. */ +#define HAVE_SA_RESTART 1 + +/* Define to 1 if you have the `setegid' function. */ +#define HAVE_SETEGID 1 + +/* Define to 1 if you have the `seteuid' function. */ +#define HAVE_SETEUID 1 + +/* Define to 1 if you have the `setlinebuf' function. */ +#define HAVE_SETLINEBUF 1 + +/* Define to 1 if you have the `setlocale' function. */ +/* #undef HAVE_SETLOCALE */ + +/* Define to 1 if you have the `setregid' function. */ +#define HAVE_SETREGID 1 + +/* Define to 1 if you have the `setreuid' function. */ +#define HAVE_SETREUID 1 + +/* Define to 1 if you have the `setrlimit' function. */ +#define HAVE_SETRLIMIT 1 + +/* Define to 1 if you have the `setvbuf' function. */ +#define HAVE_SETVBUF 1 + +/* Define to 1 if you have the `sigaction' function. */ +#define HAVE_SIGACTION 1 + +/* Define to 1 if you have the `sigsetmask' function. */ +/* #undef HAVE_SIGSETMASK */ + +/* Define to 1 if you have the `socket' function. */ +/* #undef HAVE_SOCKET */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strcmpi' function. */ +/* #undef HAVE_STRCMPI */ + +/* Define to 1 if you have the `strncasecmp' function. */ +#define HAVE_STRNCASECMP 1 + +/* Define to 1 if you have the `strncmpi' function. */ +/* #undef HAVE_STRNCMPI */ + +/* Define to 1 if you have the `strncmp' function. */ +/* #undef HAVE_STRNICMP */ + +/* Define to 1 if you have the `strcoll' function and it is properly defined. + */ +#define HAVE_STRCOLL 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `stricmp' function. */ +/* #undef HAVE_STRICMP */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strsignal' function. */ +#define HAVE_STRSIGNAL 1 + +/* Define to 1 if `n_un.n_name' is member of `struct nlist'. */ +/* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the \`union wait' type in . */ +/* #undef HAVE_UNION_WAIT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VARARGS_H */ + +/* Define to 1 if you have the `vfork' function. */ +#define HAVE_VFORK 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_VFORK_H */ + +/* Define to 1 if you have the `vprintf' function. */ +#define HAVE_VPRINTF 1 + +/* Define to 1 if you have the `wait3' function. */ +#define HAVE_WAIT3 1 + +/* Define to 1 if you have the `waitpid' function. */ +#define HAVE_WAITPID 1 + +/* Define to 1 if `fork' works. */ +#define HAVE_WORKING_FORK 1 + +/* Define to 1 if `vfork' works. */ +#define HAVE_WORKING_VFORK 1 + +/* Build host information. (not used by kmk) */ +#define MAKE_HOST "i386-pc-solaris2.11" + +/* Define to 1 to enable job server support in GNU make. */ +#define MAKE_JOBSERVER 1 + +/* Define to 1 to enable symbolic link timestamp checking. */ +#define MAKE_SYMLINKS 1 + +/* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend + on `HAVE_STRUCT_NLIST_N_UN_N_NAME */ +/* #undef NLIST_NAME_UNION */ + +/* Define to 1 if struct nlist.n_name is a pointer rather than an array. */ +/* #undef NLIST_STRUCT */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "make" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "bug-make@gnu.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "GNU make" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "GNU make 3.82" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "make" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "3.82" + +/* Define to the character that separates directories in PATH. */ +#define PATH_SEPARATOR_CHAR ':' + +/* Define to 1 if the C compiler supports function prototypes. */ +#define PROTOTYPES 1 + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to the name of the SCCS 'get' command. */ +#define SCCS_GET "get" + +/* Define to 1 if the SCCS 'get' command understands the '-G' option. */ +#define SCCS_GET_MINUS_G 1 + +/* Define to 1 if the `setvbuf' function takes the buffering type as its + second argument and the buffer pointer as the third, as on System V before + release 3. */ +/* #undef SETVBUF_REVERSED */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if the `S_IS*' macros in do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if struct stat contains a nanoseconds field */ +#define ST_MTIM_NSEC st_mtim.tv_nsec +#define ST_ATIM_NSEC st_atim.tv_nsec + +/* Define to 1 on System V Release 4. */ +/* #undef SVR4 */ + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 for Encore UMAX. */ +/* #undef UMAX */ + +/* Define to 1 for Encore UMAX 4.3 that has instead of + . */ +/* #undef UMAX4_3 */ + +/* Version number of package */ +#define VERSION "3.82" + +/* Use platform specific coding */ +/* #undef WINDOWS32 */ + +/* Define if using the dmalloc debugging malloc package */ +/* #undef WITH_DMALLOC */ + +/* Define to 1 if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +/* # undef _ALL_SOURCE */ +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +#define _FILE_OFFSET_BITS 64 + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to 1 if on MINIX. */ +/* #undef _MINIX */ + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define like PROTOTYPES; this can be used by system headers. */ +#define __PROTOTYPES 1 + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define to `int' if does not define. */ +/* #undef pid_t */ + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ + +/* Define uintmax_t if not defined in or . */ +/* #undef uintmax_t */ + +/* Define as `fork' if `vfork' does not work. */ +/* #undef vfork */ + +#include "inlined_memchr.h" + diff --git a/src/kmk/config.h.win b/src/kmk/config.h.win new file mode 100644 index 0000000..eccf0b2 --- /dev/null +++ b/src/kmk/config.h.win @@ -0,0 +1,575 @@ +/* config.h.W32 -- hand-massaged config.h file for Windows builds -*-C-*- + +Copyright (C) 1996-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#ifndef ___config_h_win +#define ___config_h_win + +/* Suppress some Visual C++ warnings. + Maybe after the code cleanup for ISO C we can remove some/all of these. */ +#if _MSC_VER > 1000 +# pragma warning(disable:4100) /* unreferenced formal parameter */ +# pragma warning(disable:4102) /* unreferenced label */ +# pragma warning(disable:4127) /* conditional expression is constant */ +# pragma warning(disable:4131) /* uses old-style declarator */ +# pragma warning(disable:4702) /* unreachable code */ +# ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS /* function or variable may be unsafe */ +# endif +# ifndef _CRT_NONSTDC_NO_WARNINGS +# define _CRT_NONSTDC_NO_WARNINGS /* functions w/o a leading underscore */ +# endif +#endif + +/* Define to 1 if the 'closedir' function returns void instead of 'int'. */ +/* #undef CLOSEDIR_VOID */ + +/* Define to one of '_getb67', 'GETB67', 'getb67' for Cray-2 and Cray-YMP + systems. This function is required for 'alloca.c' support on those systems. + */ +/* #undef CRAY_STACKSEG_END */ + +/* Define to 1 if using 'alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define to 1 if using 'getloadavg.c'. */ +#define C_GETLOADAVG 1 + +/* Define to 1 for DGUX with . */ +/* #undef DGUX */ + +/* Define to 1 if translation of program messages to the user's native + language is requested. */ +/* #undef ENABLE_NLS */ + +/* Use high resolution file timestamps if nonzero. */ +#define FILE_TIMESTAMP_HI_RES 0 + +/* Define to 1 if the 'getloadavg' function needs to be run setuid or setgid. + */ +/* #undef GETLOADAVG_PRIVILEGED */ + +/* Define to 1 if you have 'alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +/* #undef HAVE_ALLOCA_H */ + +/* Define to 1 if you have the 'atexit' function. */ +#define HAVE_ATEXIT 1 + +/* Define if your compiler conforms to the ANSI C standard. */ +#define HAVE_ANSI_COMPILER 1 + +/* Use case insensitive file names */ +/* #undef HAVE_CASE_INSENSITIVE_FS */ + +/* Define to 1 if you have the clock_gettime function. */ +/* #undef HAVE_CLOCK_GETTIME */ + +/* Embed GNU Guile support. Windows build sets this on the + compilation command line. */ +/* #undef HAVE_GUILE */ + +/* Define if the GNU dcgettext() function is already present or preinstalled. + */ +/* #undef HAVE_DCGETTEXT */ + +/* Define to 1 if you have the declaration of 'bsd_signal', and to 0 if you + don't. */ +#define HAVE_DECL_BSD_SIGNAL 0 + +/* Define to 1 if you have the declaration of 'sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL_SYS_SIGLIST 0 + +/* Define to 1 if you have the declaration of '_sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL__SYS_SIGLIST 0 + +/* Define to 1 if you have the declaration of '__sys_siglist', and to 0 if you + don't. */ +#define HAVE_DECL___SYS_SIGLIST 0 + +/* Define to 1 if you have the header file, and it defines 'DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the header file, and it defines getcwd() + and chdir(). + */ +#if (defined(_MSC_VER) || defined(__BORLANDC__)) && !defined(__INTERIX) +# define HAVE_DIRECT_H 1 +#endif + +/* Use platform specific coding */ +#define HAVE_DOS_PATHS 1 + +/* Define to 1 if you have the 'dup2' function. */ +#define HAVE_DUP2 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the 'fdopen' function. */ +#ifdef __MINGW32__ +#define HAVE_FDOPEN 1 +#endif + +/* Define to 1 if you have the 'fileno' function. */ +#define HAVE_FILENO 1 + +/* Define to 1 if you have the 'getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the 'getgroups' function. */ +/* #undef HAVE_GETGROUPS */ + +/* Define to 1 if you have the 'gethostbyname' function. */ +/* #undef HAVE_GETHOSTBYNAME */ + +/* Define to 1 if you have the 'gethostname' function. */ +/* #undef HAVE_GETHOSTNAME */ + +/* Define to 1 if you have the 'getloadavg' function. */ +/* #undef HAVE_GETLOADAVG */ + +/* Define to 1 if you have the 'getrlimit' function. */ +/* #undef HAVE_GETRLIMIT */ + +/* Define if the GNU gettext() function is already present or preinstalled. */ +/* #undef HAVE_GETTEXT */ + +/* Define to 1 if you have a standard gettimeofday function */ +#ifdef __MINGW32__ +#define HAVE_GETTIMEOFDAY 1 +#endif + +/* Define if you have the iconv() function. */ +/* #undef HAVE_ICONV */ + +/* Define to 1 if you have the header file. */ +#ifdef __MINGW32__ +#define HAVE_INTTYPES_H 1 +#endif + +/* Define to 1 if you have the 'dgc' library (-ldgc). */ +/* #undef HAVE_LIBDGC */ + +/* Define to 1 if you have the 'kstat' library (-lkstat). */ +/* #undef HAVE_LIBKSTAT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 /* bird: differs */ + +/* Define to 1 if you have the 'lstat' function. */ +/* #undef HAVE_LSTAT */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MACH_MACH_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the 'mkstemp' function. */ +/* #undef HAVE_MKSTEMP */ + +/* Define to 1 if you have the 'mktemp' function. */ +#define HAVE_MKTEMP 1 + +/* Define to 1 if you have the header file, and it defines 'DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NLIST_H */ + +/* Define to 1 if you have the 'pipe' function. */ +/* #undef HAVE_PIPE */ + +/* Define to 1 if you have the 'pstat_getdynamic' function. */ +/* #undef HAVE_PSTAT_GETDYNAMIC */ + +/* Define to 1 if you have the 'readlink' function. */ +/* #undef HAVE_READLINK */ + +/* Define to 1 if you have the 'realpath' function. */ +/* #undef HAVE_REALPATH */ + +/* Define to 1 if defines the SA_RESTART constant. */ +/* #undef HAVE_SA_RESTART */ + +/* Define to 1 if you have the 'setegid' function. */ +/* #undef HAVE_SETEGID */ + +/* Define to 1 if you have the 'seteuid' function. */ +/* #undef HAVE_SETEUID */ + +/* Define to 1 if you have the 'setlinebuf' function. */ +/* #undef HAVE_SETLINEBUF */ + +/* Define to 1 if you have the 'setlocale' function. */ +/*#define HAVE_SETLOCALE 1*/ + +/* Define to 1 if you have the 'setregid' function. */ +/* #undef HAVE_SETREGID */ + +/* Define to 1 if you have the 'setreuid' function. */ +/* #undef HAVE_SETREUID */ + +/* Define to 1 if you have the 'setrlimit' function. */ +/* #undef HAVE_SETRLIMIT */ + +/* Define to 1 if you have the 'setvbuf' function. */ +#define HAVE_SETVBUF 1 + +/* Define to 1 if you have the 'sigaction' function. */ +/* #undef HAVE_SIGACTION */ + +/* Define to 1 if you have the 'sigsetmask' function. */ +/* #undef HAVE_SIGSETMASK */ + +/* Define to 1 if you have the 'socket' function. */ +/* #undef HAVE_SOCKET */ + +/* Define to 1 if you have the header file. */ +#if defined(__MINGW32__) || _MSC_VER >= 1600 /* bird: added latter */ +# define HAVE_STDINT_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the 'strcasecmp' function. */ +#ifdef __MINGW32__ +#define HAVE_STRCASECMP 1 +#endif + +/* Define to 1 if you have the 'strcmpi' function. */ +#define HAVE_STRCMPI 1 + +/* Define to 1 if you have the 'strcoll' function and it is properly defined. + */ +#define HAVE_STRCOLL 1 + +/* Define to 1 if you have the 'strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the 'strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the 'stricmp' function. */ +#define HAVE_STRICMP 1 + +/* Define to 1 if you have the header file. */ +/* #define HAVE_STRINGS_H 1 */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the 'strncasecmp' function. */ +#ifdef __MINGW32__ +#define HAVE_STRNCASECMP 1 +#endif + +/* Define to 1 if you have the 'strncmpi' function. */ +/* #undef HAVE_STRNCMPI */ + +/* Define to 1 if you have the 'strndup' function. */ +/* #undef HAVE_STRNDUP */ + +/* Define to 1 if you have the 'strnicmp' function. */ +/*#ifdef __MINGW32__ - bird */ +#define HAVE_STRNICMP 1 +/* #endif - bird */ + +/* Define to 1 if you have the 'strsignal' function. */ +/* #undef HAVE_STRSIGNAL */ + +/* Define to 1 if you have the `isatty' function. */ +#define HAVE_ISATTY 1 + +/* Define to 1 if you have the `ttyname' function. */ +#define HAVE_TTYNAME 1 +char *ttyname (int); + +/* Define to 1 if 'n_un.n_name' is a member of 'struct nlist'. */ +/* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */ + +/* Define to 1 if you have the header file, and it defines 'DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file, and it defines 'DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#ifdef __MINGW32__ +#define HAVE_SYS_PARAM_H 1 +#endif + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_RESOURCE_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +#ifdef __MINGW32__ +#define HAVE_SYS_TIME_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_WAIT_H */ + +/* Define to 1 if you have the \'union wait' type in . */ +/* #undef HAVE_UNION_WAIT */ + +/* Define to 1 if you have the header file. */ +#ifdef __MINGW32__ +#define HAVE_UNISTD_H 1 +#endif + +/* Define to 1 if you have the 'wait3' function. */ +/* #undef HAVE_WAIT3 */ + +/* Define to 1 if you have the 'waitpid' function. */ +/* #undef HAVE_WAITPID */ + +/* Build host information. (not used by kmk) */ +#define MAKE_HOST "Windows32" + +/* Define to 1 to enable job server support in GNU make. */ +#define MAKE_JOBSERVER 1 + +/* Define to 1 to enable 'load' support in GNU make. */ +#define MAKE_LOAD 1 + +/* Define to 1 to enable symbolic link timestamp checking. */ +/* #undef MAKE_SYMLINKS */ + +/* Define to 1 if your 'struct nlist' has an 'n_un' member. Obsolete, depend + on 'HAVE_STRUCT_NLIST_N_UN_N_NAME */ +/* #undef NLIST_NAME_UNION */ + +/* Define to 1 if struct nlist.n_name is a pointer rather than an array. */ +/* #undef NLIST_STRUCT */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of this package (needed by automake) */ +#define PACKAGE "make" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "bug-make@gnu.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "kmk" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "http://kbuild.org/" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "4.2.1" + +/* Define to the character that separates directories in PATH. */ +#define PATH_SEPARATOR_CHAR ';' + +/* Define as the return type of signal handlers ('int' or 'void'). */ +#define RETSIGTYPE void + +/* Define to the name of the SCCS 'get' command. */ +#define SCCS_GET "echo no sccs get" + +/* Define this if the SCCS 'get' command understands the '-G' option. */ +/* #undef SCCS_GET_MINUS_G */ + +/* Define to 1 if the 'setvbuf' function takes the buffering type as its + second argument and the buffer pointer as the third, as on System V before + release 3. */ +/* #undef SETVBUF_REVERSED */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if the 'S_IS*' macros in do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if struct stat contains a nanoseconds field */ +#define ST_MTIM_NSEC st_mtim.tv_nsec /* bird */ +#define ST_ATIM_NSEC st_atim.tv_nsec /* bird */ + +/* Define to 1 on System V Release 4. */ +/* #undef SVR4 */ + +/* Define to 1 if you can safely include both and . */ +#ifdef __MINGW32__ +#define TIME_WITH_SYS_TIME 1 +#endif + +/* Define to 1 for Encore UMAX. */ +/* #undef UMAX */ + +/* Define to 1 for Encore UMAX 4.3 that has instead of + . */ +/* #undef UMAX4_3 */ + +/* Version number of package */ +#define VERSION "4.2.1" + +/* Define if using the dmalloc debugging malloc package */ +/* #undef WITH_DMALLOC */ + +/* Define to 1 if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +/* # undef _ALL_SOURCE */ +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to 1 if on MINIX. */ +/* #undef _MINIX */ + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to 1 if you need to in order for 'stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define to empty if 'const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to 'int' if doesn't define. */ +#define gid_t int + +/* Define to 'int' if does not define. */ +/* Note (bird)! sub_proc.c needs this to be pointer sized. */ +#define pid_t intptr_t + +/* Define to 'int' if doesn't define. */ +#define uid_t int + +/* Define uintmax_t if not defined in or . */ +#if !HAVE_STDINT_H && !HAVE_INTTYPES_H +# if 0 +# define uintmax_t unsigned long +# else +# define uintmax_t unsigned __int64 +# endif +#endif + +/* Define if you have that is POSIX.1 compatible. */ +/* #undef HAVE_SYS_WAIT_H */ + +/* Define to the installation directory for locales. */ +#define LOCALEDIR "" + +/* + * Refer to README.W32 for info on the following settings + */ + + +/* + * If you have a shell that does not grok 'sh -c quoted-command-line' + * correctly, you need this setting. Please see below for specific + * shell support. + */ +/*#define BATCH_MODE_ONLY_SHELL 1 */ + +/* + * Define if you have the Cygnus "Cygwin" GNU Windows32 tool set. + * Do NOT define BATCH_MODE_ONLY_SHELL if you define HAVE_CYGWIN_SHELL + */ +/*#define HAVE_CYGWIN_SHELL 1 */ + +/* + * Define if you have the MKS tool set or shell. Do NOT define + * BATCH_MODE_ONLY_SHELL if you define HAVE_MKS_SHELL + */ +/*#define HAVE_MKS_SHELL 1 */ + +/* + * Enforce the mutual exclusivity restriction. + */ +#ifdef HAVE_MKS_SHELL +#undef BATCH_MODE_ONLY_SHELL +#endif + +#ifdef HAVE_CYGWIN_SHELL +#undef BATCH_MODE_ONLY_SHELL +#endif + +/* bird stat hacks. */ +#include +#include +#include "nt/ntstat.h" + +/* bird dirent hack. */ +#define _DIRENT_H /* see w32/dirent.h */ +#include "nt/ntdir.h" +#define _DIRENT_HAVE_D_NAMLEN 1 +#define _DIRENT_HAVE_D_TYPE 1 + +/* bird: Not sure if this is necessary any more... */ +#define BATCH_MODE_ONLY_SHELL + +#include "inlined_memchr.h" + +/* bird: Include mscfakes.h to make sure we have all it's tricks applied. */ +#ifndef ___mscfakes_h +# include "kmkbuiltin/mscfakes.h" +#endif + +/* + * Map posixfcn.c stuff to non-conflicting names. + */ +#include +#include + +#define tmpfile posixfcn_tmpfile +FILE *posixfcn_tmpfile(void); + +#define isatty posixfcn_isatty +int posixfcn_isatty(int fd); + +#endif /* bird */ + diff --git a/src/kmk/config/.gitignore b/src/kmk/config/.gitignore new file mode 100644 index 0000000..d11a488 --- /dev/null +++ b/src/kmk/config/.gitignore @@ -0,0 +1,12 @@ +ar-lib +compile +config.guess +config.rpath +config.sub +depcomp +install-sh +mdate-sh +missing +texinfo.tex +*.m4 +!dospaths.m4 diff --git a/src/kmk/config/ChangeLog.1 b/src/kmk/config/ChangeLog.1 new file mode 100644 index 0000000..8549501 --- /dev/null +++ b/src/kmk/config/ChangeLog.1 @@ -0,0 +1,49 @@ +2012-01-15 Paul Smith + + * dospaths.m4: Use AC_LANG_PROGRAM to encapsulate the test code. + Fixes Savannah bug #35256. Patch from Sebastian Pipping. + +2006-03-09 Paul Smith + + * dospaths.m4: Add MSYS to the list of targets allowing DOS-style + pathnames. Reported by David Ergo . + +2005-07-01 Paul D. Smith + + * Makefile.am (EXTRA_DIST): Added more M4 files to EXTRA_DIST, so + users can re-run aclocal. + +2003-04-30 Paul D. Smith + + * dospaths.m4: New macro to test for DOS-style pathnames, based on + coreutils 5.0 "dos.m4" by Jim Meyering. + +2002-04-21 gettextize + + * codeset.m4: New file, from gettext-0.11.1. + * gettext.m4: New file, from gettext-0.11.1. + * glibc21.m4: New file, from gettext-0.11.1. + * iconv.m4: New file, from gettext-0.11.1. + * isc-posix.m4: New file, from gettext-0.11.1. + * lcmessage.m4: New file, from gettext-0.11.1. + * lib-ld.m4: New file, from gettext-0.11.1. + * lib-link.m4: New file, from gettext-0.11.1. + * lib-prefix.m4: New file, from gettext-0.11.1. + * progtest.m4: New file, from gettext-0.11.1. + * Makefile.am: New file. + + +Copyright (C) 2002-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . diff --git a/src/kmk/config/Makefile.am b/src/kmk/config/Makefile.am new file mode 100644 index 0000000..7bce036 --- /dev/null +++ b/src/kmk/config/Makefile.am @@ -0,0 +1,18 @@ +# -*-Makefile-*-, or close enough +# Copyright (C) 2002-2016 Free Software Foundation, Inc. +# This file is part of GNU Make. +# +# GNU Make is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) +# any later version. +# +# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +# Autoconf / automake know how to handle this directory. diff --git a/src/kmk/config/dospaths.m4 b/src/kmk/config/dospaths.m4 new file mode 100644 index 0000000..9aa9814 --- /dev/null +++ b/src/kmk/config/dospaths.m4 @@ -0,0 +1,33 @@ +# Test if the system uses DOS-style pathnames (drive specs and backslashes) +# By Paul Smith . Based on dos.m4 by Jim Meyering. +# +# Copyright (C) 1993-2016 Free Software Foundation, Inc. +# This file is part of GNU Make. +# +# GNU Make is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +AC_DEFUN([pds_AC_DOS_PATHS], [ + AC_CACHE_CHECK([whether system uses MSDOS-style paths], [ac_cv_dos_paths], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#if !defined _WIN32 && !defined __WIN32__ && !defined __MSDOS__ && !defined __EMX__ && !defined __MSYS__ && !defined __CYGWIN__ +neither MSDOS nor Windows nor OS2 +#endif +]])], + [ac_cv_dos_paths=yes], + [ac_cv_dos_paths=no])]) + + AS_IF([test x"$ac_cv_dos_paths" = xyes], + [ AC_DEFINE_UNQUOTED([HAVE_DOS_PATHS], 1, + [Define if the system uses DOS-style pathnames.])]) +]) diff --git a/src/kmk/configh.dos.template b/src/kmk/configh.dos.template new file mode 100644 index 0000000..c43e644 --- /dev/null +++ b/src/kmk/configh.dos.template @@ -0,0 +1,113 @@ +/* configh.dos -- hand-massaged config.h file for MS-DOS builds -*-C-*- + +Copyright (C) 1994-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +/* Include this header to make __DJGPP_MINOR__ available because DJGPP ports + of GCC 4.3.0 and later no longer do it automatically. */ +#include + +/* Many things are defined already by a system header. */ +#include + +#if __DJGPP__ > 2 || __DJGPP_MINOR__ > 1 + +/* Define to 1 if 'sys_siglist' is declared by or . */ +# define SYS_SIGLIST_DECLARED 1 + +/* Define to 1 if the C library defines the variable '_sys_siglist'. */ +# define HAVE_DECL_SYS_SIGLIST 1 + +#else + +/* Define NSIG. */ +# define NSIG SIGMAX + +#endif + +/* Use high resolution file timestamps if nonzero. */ +#define FILE_TIMESTAMP_HI_RES 0 + +/* Define to 1 if you have 'alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have the fdopen function. */ +#define HAVE_FDOPEN 1 + +/* Define to 1 if you have the 'getgroups' function. */ +#define HAVE_GETGROUPS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the mkstemp function. */ +#define HAVE_MKSTEMP 1 + +/* Define to 1 if you have the 'mktemp' function. */ +#define HAVE_MKTEMP 1 + +/* Define to 1 if you have the 'setlinebuf' function. */ +#define HAVE_SETLINEBUF 1 + +/* Define to 1 if you have the 'setvbuf' function. */ +#define HAVE_SETVBUF 1 + +#define SCCS_GET "get" + +/* Define to 'unsigned long' or 'unsigned long long' + if doesn't define. */ +#define uintmax_t unsigned long long + +/* Define the type of the first arg to select(). */ +#define fd_set_size_t int + +/* Define to 1 if you have the select function. */ +#define HAVE_SELECT 1 + +/* Define to 1 if you have the stricmp function. */ +#define HAVE_STRICMP 1 + +/* Define to 1 if you have the 'strncasecmp' function. */ +#define HAVE_STRNCASECMP 1 + +/* Name of the package */ +#define PACKAGE "%PACKAGE%" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "bug-%PACKAGE%@gnu.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "GNU %PACKAGE%" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "GNU %PACKAGE% %VERSION%" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "%PACKAGE%" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "%VERSION%" + +/* Output sync sypport */ +#define NO_OUTPUT_SYNC + +/* Version number of package */ +#define VERSION "%VERSION%" + +/* Build host information. */ +#define MAKE_HOST "i386-pc-msdosdjgpp" + +/* Grok DOS paths (drive specs and backslash path element separators) */ +#define HAVE_DOS_PATHS diff --git a/src/kmk/configure.ac b/src/kmk/configure.ac new file mode 100644 index 0000000..d950182 --- /dev/null +++ b/src/kmk/configure.ac @@ -0,0 +1,534 @@ +# Process this file with autoconf to produce a configure script. +# +# Copyright (C) 1993-2016 Free Software Foundation, Inc. +# This file is part of GNU Make. +# +# GNU Make is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +AC_INIT([GNU make],[4.2.1],[bug-make@gnu.org]) + +AC_PREREQ([2.69]) + +# Autoconf setup +AC_CONFIG_AUX_DIR([config]) +AC_CONFIG_SRCDIR([vpath.c]) +AC_CONFIG_HEADERS([config.h]) + +# Automake setup +# We have to enable "foreign" because ChangeLog is auto-generated +# We cannot enable -Werror because gettext 0.18.1 has invalid content +# When we update gettext to 0.18.3 or better we can add it again. +# bird: Added subdir-objects +AM_INIT_AUTOMAKE([1.15 foreign -Werror -Wall subdir-objects]) + +# Checks for programs. +AC_USE_SYSTEM_EXTENSIONS +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_RANLIB +AC_PROG_CPP +AC_CHECK_PROG([AR], [ar], [ar], [ar]) +# Perl is needed for the test suite (only) +AC_CHECK_PROG([PERL], [perl], [perl], [perl]) + +# Needed for w32/Makefile.am +AM_PROG_AR + +# Specialized system macros +AC_CANONICAL_HOST +AC_AIX +AC_ISC_POSIX +AC_MINIX + +# Enable gettext, in "external" mode. +# bird: causes trouble when it doesn't find 'po' in SUBDIRS, so skip it. +#AM_GNU_GETTEXT_VERSION([0.19.4]) +#AM_GNU_GETTEXT([external]) + +# This test must come as early as possible after the compiler configuration +# tests, because the choice of the file model can (in principle) affect +# whether functions and headers are available, whether they work, etc. +AC_SYS_LARGEFILE + +# Checks for libraries. +AC_SEARCH_LIBS([getpwnam], [sun]) + +# Checks for header files. +AC_HEADER_STDC +AC_HEADER_DIRENT +AC_HEADER_STAT +AC_HEADER_TIME +AC_CHECK_HEADERS([stdlib.h locale.h unistd.h limits.h fcntl.h string.h \ + memory.h sys/param.h sys/resource.h sys/time.h sys/timeb.h \ + sys/select.h]) + +AM_PROG_CC_C_O +AC_C_CONST +AC_TYPE_SIGNAL +AC_TYPE_UID_T +AC_TYPE_PID_T +AC_TYPE_OFF_T +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_TYPE_UINTMAX_T + +# Find out whether our struct stat returns nanosecond resolution timestamps. + +AC_STRUCT_ST_MTIM_NSEC +AC_STRUCT_ST_ATIM_NSEC +AC_CACHE_CHECK([whether to use high resolution file timestamps], + [make_cv_file_timestamp_hi_res], +[ make_cv_file_timestamp_hi_res=no + AS_IF([test "$ac_cv_struct_st_mtim_nsec" != no], + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#if HAVE_INTTYPES_H +# include +#endif]], + [[char a[0x7fffffff < (uintmax_t)-1 >> 30 ? 1 : -1];]])], + [make_cv_file_timestamp_hi_res=yes]) + ])]) +AS_IF([test "$make_cv_file_timestamp_hi_res" = yes], [val=1], [val=0]) +AC_DEFINE_UNQUOTED([FILE_TIMESTAMP_HI_RES], [$val], + [Use high resolution file timestamps if nonzero.]) + +AS_IF([test "$make_cv_file_timestamp_hi_res" = yes], +[ # Solaris 2.5.1 needs -lposix4 to get the clock_gettime function. + # Solaris 7 prefers the library name -lrt to the obsolescent name -lposix4. + AC_SEARCH_LIBS([clock_gettime], [rt posix4]) + AS_IF([test "$ac_cv_search_clock_gettime" != no], + [ AC_DEFINE([HAVE_CLOCK_GETTIME], [1], + [Define to 1 if you have the clock_gettime function.]) + ]) +]) + +# Check for DOS-style pathnames. +pds_AC_DOS_PATHS + +# See if we have a standard version of gettimeofday(). Since actual +# implementations can differ, just make sure we have the most common +# one. +AC_CACHE_CHECK([for standard gettimeofday], [ac_cv_func_gettimeofday], + [ac_cv_func_gettimeofday=no + AC_RUN_IFELSE([AC_LANG_SOURCE([[#include + #include /* kmk/darwin: for exit */ + int main () + { + struct timeval t; t.tv_sec = -1; t.tv_usec = -1; + exit (gettimeofday (&t, 0) != 0 + || t.tv_sec < 0 || t.tv_usec < 0); + }]])], + [ac_cv_func_gettimeofday=yes], + [ac_cv_func_gettimeofday=no], + [ac_cv_func_gettimeofday="no (cross-compiling)"])]) +AS_IF([test "$ac_cv_func_gettimeofday" = yes], +[ AC_DEFINE([HAVE_GETTIMEOFDAY], [1], + [Define to 1 if you have a standard gettimeofday function]) +]) + +AC_CHECK_FUNCS([strdup strndup mkstemp mktemp fdopen fileno \ + dup dup2 getcwd realpath sigsetmask sigaction \ + getgroups seteuid setegid setlinebuf setreuid setregid \ + getrlimit setrlimit setvbuf pipe strerror strsignal \ + lstat readlink atexit isatty ttyname pselect]) + +# We need to check declarations, not just existence, because on Tru64 this +# function is not declared without special flags, which themselves cause +# other problems. We'll just use our own. +AC_CHECK_DECLS([bsd_signal], [], [], [[#define _GNU_SOURCE 1 +#include ]]) + +AC_FUNC_FORK + +AC_FUNC_SETVBUF_REVERSED + +# Rumor has it that strcasecmp lives in -lresolv on some odd systems. +# It doesn't hurt much to use our own if we can't find it so I don't +# make the effort here. +AC_CHECK_FUNCS([strcasecmp strncasecmp strcmpi strncmpi stricmp strnicmp]) + +# strcoll() is used by the GNU glob library +AC_FUNC_STRCOLL + +AC_FUNC_ALLOCA +AC_FUNC_CLOSEDIR_VOID + +# bird: This guile detection does not work on rhel4. Disabled it all since we doesn't care about guile. +## See if the user wants to add (or not) GNU Guile support +#PKG_PROG_PKG_CONFIG +#AC_ARG_WITH([guile], [AS_HELP_STRING([--with-guile], +# [Support GNU Guile for embedded scripting])]) +# +## For some strange reason, at least on Ubuntu, each version of Guile +## comes with it's own PC file so we have to specify them as individual +## packages. Ugh. +#AS_IF([test "x$with_guile" != xno], +#[ PKG_CHECK_MODULES([GUILE], [guile-2.0], [have_guile=yes], +# [PKG_CHECK_MODULES([GUILE], [guile-1.8], [have_guile=yes], +# [have_guile=no])]) +#]) +# +#AS_IF([test "$have_guile" = yes], +# [AC_DEFINE([HAVE_GUILE], [1], [Embed GNU Guile support])]) +# +#AM_CONDITIONAL([HAVE_GUILE], [test "$have_guile" = yes]) + +AC_FUNC_GETLOADAVG + +# AC_FUNC_GETLOADAVG is documented to set the NLIST_STRUCT value, but it +# doesn't. So, we will. + +AS_IF([test "$ac_cv_header_nlist_h" = yes], +[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[struct nlist nl; + nl.n_name = "string"; + return 0;]])], + [make_cv_nlist_struct=yes], + [make_cv_nlist_struct=no]) + AS_IF([test "$make_cv_nlist_struct" = yes], + [ AC_DEFINE([NLIST_STRUCT], [1], + [Define to 1 if struct nlist.n_name is a pointer rather than an array.]) + ]) +]) + +AC_CHECK_DECLS([sys_siglist, _sys_siglist, __sys_siglist], , , + [AC_INCLUDES_DEFAULT +#include +/* NetBSD declares sys_siglist in unistd.h. */ +#if HAVE_UNISTD_H +# include +#endif +]) + + +# Check out the wait reality. +AC_CHECK_HEADERS([sys/wait.h],[],[],[[#include ]]) +AC_CHECK_FUNCS([waitpid wait3]) +AC_CACHE_CHECK([for union wait], [make_cv_union_wait], +[ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include +#include ]], + [[union wait status; int pid; pid = wait (&status); +#ifdef WEXITSTATUS +/* Some POSIXoid systems have both the new-style macros and the old + union wait type, and they do not work together. If union wait + conflicts with WEXITSTATUS et al, we don't want to use it at all. */ + if (WEXITSTATUS (status) != 0) pid = -1; +#ifdef WTERMSIG + /* If we have WEXITSTATUS and WTERMSIG, just use them on ints. */ + -- blow chunks here -- +#endif +#endif +#ifdef HAVE_WAITPID + /* Make sure union wait works with waitpid. */ + pid = waitpid (-1, &status, 0); +#endif + ]])], + [make_cv_union_wait=yes], + [make_cv_union_wait=no]) +]) +AS_IF([test "$make_cv_union_wait" = yes], +[ AC_DEFINE([HAVE_UNION_WAIT], [1], + [Define to 1 if you have the 'union wait' type in .]) +]) + + +# If we're building on Windows/DOS/OS/2, add some support for DOS drive specs. +AS_IF([test "$PATH_SEPARATOR" = ';'], +[ AC_DEFINE([HAVE_DOS_PATHS], [1], + [Define to 1 if your system requires backslashes or drive specs in pathnames.]) +]) + +# See if the user wants to use pmake's "customs" distributed build capability +AC_SUBST([REMOTE]) REMOTE=stub +use_customs=false +AC_ARG_WITH([customs], +[AC_HELP_STRING([--with-customs=DIR], + [enable remote jobs via Customs--see README.customs])], +[ AS_CASE([$withval], [n|no], [:], + [make_cppflags="$CPPFLAGS" + AS_CASE([$withval], + [y|ye|yes], [:], + [CPPFLAGS="$CPPFLAGS -I$with_customs/include/customs" + make_ldflags="$LDFLAGS -L$with_customs/lib"]) + CF_NETLIBS + AC_CHECK_HEADER([customs.h], + [use_customs=true + REMOTE=cstms + LIBS="$LIBS -lcustoms" LDFLAGS="$make_ldflags"], + [with_customs=no + CPPFLAGS="$make_cppflags" make_badcust=yes]) + ]) +]) + +# Tell automake about this, so it can include the right .c files. +AM_CONDITIONAL([USE_CUSTOMS], [test "$use_customs" = true]) + +# See if the user asked to handle case insensitive file systems. +AH_TEMPLATE([HAVE_CASE_INSENSITIVE_FS], [Use case insensitive file names]) +AC_ARG_ENABLE([case-insensitive-file-system], + AC_HELP_STRING([--enable-case-insensitive-file-system], + [assume file systems are case insensitive]), + [AS_IF([test "$enableval" = yes], [AC_DEFINE([HAVE_CASE_INSENSITIVE_FS])])]) + +# See if we can handle the job server feature, and if the user wants it. +AC_ARG_ENABLE([job-server], + AC_HELP_STRING([--disable-job-server], + [disallow recursive make communication during -jN]), + [make_cv_job_server="$enableval" user_job_server="$enableval"], + [make_cv_job_server="yes"]) + +AS_IF([test "$ac_cv_func_waitpid" = no && test "$ac_cv_func_wait3" = no], + [has_wait_nohang=no], + [has_wait_nohang=yes]) + +AC_CACHE_CHECK([for SA_RESTART], [make_cv_sa_restart], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[return SA_RESTART;]])], + [make_cv_sa_restart=yes], + [make_cv_sa_restart=no])]) + +AS_IF([test "$make_cv_sa_restart" != no], +[ AC_DEFINE([HAVE_SA_RESTART], [1], + [Define to 1 if defines the SA_RESTART constant.]) +]) + +# Only allow jobserver on systems that support it +AS_CASE([/$ac_cv_func_pipe/$ac_cv_func_sigaction/$make_cv_sa_restart/$has_wait_nohang/], + [*/no/*], [make_cv_job_server=no]) + +# Also supported on OS2 and MinGW +AS_CASE([$host_os], [os2*|mingw*], [make_cv_job_server=yes]) + +# If we support it and the user didn't disable it, build with jobserver +AS_CASE([/$make_cv_job_server/$user_job_server/], + [*/no/*], [: no jobserver], + [AC_DEFINE(MAKE_JOBSERVER, 1, + [Define to 1 to enable job server support in GNU make.]) + ]) + +# If dl*() functions are supported we can enable the load operation +AC_CHECK_DECLS([dlopen, dlsym, dlerror], [], [], + [[#include ]]) + +AC_ARG_ENABLE([load], + AC_HELP_STRING([--disable-load], + [disable support for the 'load' operation]), + [make_cv_load="$enableval" user_load="$enableval"], + [make_cv_load="yes"]) + +AS_CASE([/$ac_cv_have_decl_dlopen/$ac_cv_have_decl_dlsym/$ac_cv_have_decl_dlerror/], + [*/no/*], [make_cv_load=no]) + +# We might need -ldl +AS_IF([test "$make_cv_load" = yes], [ + AC_SEARCH_LIBS([dlopen], [dl], [], [make_cv_load=]) + ]) + +AS_CASE([/$make_cv_load/$user_load/], + [*/no/*], [make_cv_load=no], + [AC_DEFINE(MAKE_LOAD, 1, + [Define to 1 to enable 'load' support in GNU make.]) + ]) + +# If we want load support, we might need to link with export-dynamic. +# See if we can figure it out. Unfortunately this is very difficult. +# For example passing -rdynamic to the SunPRO linker gives a warning +# but succeeds and creates a shared object, not an executable! +AS_IF([test "$make_cv_load" = yes], [ + AC_MSG_CHECKING([If the linker accepts -Wl,--export-dynamic]) + old_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -Wl,--export-dynamic" + AC_LINK_IFELSE([AC_LANG_SOURCE([int main(){}])], + [AC_MSG_RESULT([yes]) + AC_SUBST([AM_LDFLAGS], [-Wl,--export-dynamic])], + [AC_MSG_RESULT([no]) + AC_MSG_CHECKING([If the linker accepts -rdynamic]) + LDFLAGS="$old_LDFLAGS -rdynamic" + AC_LINK_IFELSE([AC_LANG_SOURCE([int main(){}])], + [AC_MSG_RESULT([yes]) + AC_SUBST([AM_LDFLAGS], [-rdynamic])], + [AC_MSG_RESULT([no])]) + ]) + LDFLAGS="$old_LDFLAGS" +]) + +# if we have both lstat() and readlink() then we can support symlink +# timechecks. +AS_IF([test "$ac_cv_func_lstat" = yes && test "$ac_cv_func_readlink" = yes], + [ AC_DEFINE([MAKE_SYMLINKS], [1], + [Define to 1 to enable symbolic link timestamp checking.]) +]) + +# Find the SCCS commands, so we can include them in our default rules. + +AC_CACHE_CHECK([for location of SCCS get command], [make_cv_path_sccs_get], [ + AS_IF([test -f /usr/sccs/get], + [make_cv_path_sccs_get=/usr/sccs/get], + [make_cv_path_sccs_get=get]) +]) +AC_DEFINE_UNQUOTED([SCCS_GET], ["$make_cv_path_sccs_get"], + [Define to the name of the SCCS 'get' command.]) + +ac_clean_files="$ac_clean_files s.conftest conftoast" # Remove these later. +AS_IF([(/usr/sccs/admin -n s.conftest || admin -n s.conftest) >/dev/null 2>&1 && + test -f s.conftest], +[ # We successfully created an SCCS file. + AC_CACHE_CHECK([if SCCS get command understands -G], [make_cv_sys_get_minus_G], + [AS_IF([$make_cv_path_sccs_get -Gconftoast s.conftest >/dev/null 2>&1 && + test -f conftoast], + [make_cv_sys_get_minus_G=yes], + [make_cv_sys_get_minus_G=no]) + ]) + AS_IF([test "$make_cv_sys_get_minus_G" = yes], + [AC_DEFINE([SCCS_GET_MINUS_G], [1], + [Define to 1 if the SCCS 'get' command understands the '-G' option.]) + ]) +]) +rm -f s.conftest conftoast + +## bird: always use our glob impl. Avoids trouble with newish glibc. +# Check the system to see if it provides GNU glob. If not, use our +# local version. +#x# AC_CACHE_CHECK([if system libc has GNU glob], [make_cv_sys_gnu_glob], +#x# [ AC_EGREP_CPP([gnu glob],[ +#x# #include +#x# #include +#x# #include +#x# +#x# #define GLOB_INTERFACE_VERSION 1 +#x# #if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1 +#x# # include +#x# # if _GNU_GLOB_INTERFACE_VERSION == GLOB_INTERFACE_VERSION +#x# gnu glob +#x# # endif +#x# #endif], +#x# [make_cv_sys_gnu_glob=yes], +#x# [make_cv_sys_gnu_glob=no])]) +#x# AS_IF([test "$make_cv_sys_gnu_glob" = no], +AS_IF([test yes = yes], +[ GLOBINC='-I$(srcdir)/glob' + GLOBLIB=glob/libglob.a + make_cv_sys_gnu_glob=no +]) +AC_SUBST([GLOBINC]) +AC_SUBST([GLOBLIB]) + +# Tell automake about this, so it can build the right .c files. +AM_CONDITIONAL([USE_LOCAL_GLOB], [test "$make_cv_sys_gnu_glob" = no]) + +# Let the makefile know what our build host is + +AC_DEFINE_UNQUOTED([MAKE_HOST],["$host"],[Build host information.]) +MAKE_HOST="$host" +AC_SUBST([MAKE_HOST]) + +w32_target_env=no +AM_CONDITIONAL([WINDOWSENV], [false]) + +AS_CASE([$host], + [*-*-mingw32], + [AM_CONDITIONAL([WINDOWSENV], [true]) + w32_target_env=yes + AC_DEFINE([WINDOWS32], [1], [Use platform specific coding]) + AC_DEFINE([HAVE_DOS_PATHS], [1], [Use platform specific coding]) + ]) + +AC_DEFINE_UNQUOTED([PATH_SEPARATOR_CHAR],['$PATH_SEPARATOR'], + [Define to the character that separates directories in PATH.]) + +# Include the Maintainer's Makefile section, if it's here. + +MAINT_MAKEFILE=/dev/null +AS_IF([test -r "$srcdir/maintMakefile"], +[ MAINT_MAKEFILE="$srcdir/maintMakefile" +]) +AC_SUBST_FILE([MAINT_MAKEFILE]) + +# Allow building with dmalloc +AM_WITH_DMALLOC + +# Forcibly disable SET_MAKE. If it's set it breaks things like the test +# scripts, etc. +SET_MAKE= + +# Sanity check and inform the user of what we found + +AS_IF([test "x$make_badcust" = xyes], [ +echo +echo "WARNING: --with-customs specified but no customs.h could be found;" +echo " disabling Customs support." +echo +]) + +AS_CASE([$with_customs], +[""|n|no|y|ye|yes], [:], +[AS_IF([test -f "$with_customs/lib/libcustoms.a"], [:], +[ echo + echo "WARNING: '$with_customs/lib' does not appear to contain the" + echo " Customs library. You must build and install Customs" + echo " before compiling GNU make." + echo +])]) + +AS_IF([test "x$has_wait_nohang" = xno], +[ echo + echo "WARNING: Your system has neither waitpid() nor wait3()." + echo " Without one of these, signal handling is unreliable." + echo " You should be aware that running GNU make with -j" + echo " could result in erratic behavior." + echo +]) + +AS_IF([test "x$make_cv_job_server" = xno && test "x$user_job_server" = xyes], +[ echo + echo "WARNING: Make job server requires a POSIX-ish system that" + echo " supports the pipe(), sigaction(), and either" + echo " waitpid() or wait3() functions. Your system doesn't" + echo " appear to provide one or more of those." + echo " Disabling job server support." + echo +]) + +AS_IF([test "x$make_cv_load" = xno && test "x$user_load" = xyes], +[ echo + echo "WARNING: 'load' support requires a POSIX-ish system that" + echo " supports the dlopen(), dlsym(), and dlerror() functions." + echo " Your system doesn't appear to provide one or more of these." + echo " Disabling 'load' support." + echo +]) + +# Specify what files are to be created. +# bird: Removed po/Makefile.in. +#AC_CONFIG_FILES([Makefile glob/Makefile po/Makefile.in config/Makefile \ +# doc/Makefile w32/Makefile tests/config-flags.pm]) +AC_CONFIG_FILES([Makefile glob/Makefile config/Makefile \ + doc/Makefile w32/Makefile tests/config-flags.pm]) + +# OK, do it! + +AC_OUTPUT + +# We only generate the build.sh if we have a build.sh.in; we won't have +# one before we've created a distribution. +AS_IF([test -f "$srcdir/build.sh.in"], +[ ./config.status --file build.sh + chmod +x build.sh +]) + +dnl Local Variables: +dnl comment-start: "dnl " +dnl comment-end: "" +dnl comment-start-skip: "\\bdnl\\b\\s *" +dnl compile-command: "make configure config.h.in" +dnl End: diff --git a/src/kmk/configure.bat b/src/kmk/configure.bat new file mode 100644 index 0000000..3c41f38 --- /dev/null +++ b/src/kmk/configure.bat @@ -0,0 +1,60 @@ +@echo off +rem Copyright (C) 1994-2016 Free Software Foundation, Inc. +rem This file is part of GNU Make. +rem +rem GNU Make is free software; you can redistribute it and/or modify it under +rem the terms of the GNU General Public License as published by the Free +rem Software Foundation; either version 3 of the License, or (at your option) +rem any later version. +rem +rem GNU Make is distributed in the hope that it will be useful, but WITHOUT +rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for. +rem more details. +rem +rem You should have received a copy of the GNU General Public License along +rem with this program. If not, see . + +echo Configuring MAKE for DJGPP + +rem The SmallEnv trick protects against too small environment block, +rem in which case the values will be truncated and the whole thing +rem goes awry. COMMAND.COM will say "Out of environment space", but +rem many people don't care, so we force them to care by refusing to go. + +rem Where is the srcdir? +set XSRC=. +if not "%XSRC%"=="." goto SmallEnv +if "%1%"=="" goto SrcDone +set XSRC=%1 +if not "%XSRC%"=="%1" goto SmallEnv + +:SrcDone + +update %XSRC%/configh.dos ./config.h + +rem Do they have Make? +redir -o junk.$$$ -eo make -n -f NUL +rem REDIR will return 1 if it cannot run Make. +rem If it can run Make, it will usually return 2, +rem but 0 is also OK with us. +if errorlevel 2 goto MakeOk +if not errorlevel 1 goto MakeOk +if exist junk.$$$ del junk.$$$ +echo No Make program found--use DOSBUILD.BAT to build Make. +goto End + +rem They do have Make. Generate the Makefile. + +:MakeOk +del junk.$$$ +update %XSRC%/Makefile.DOS ./Makefile +echo Done. +if not "%XSRC%"=="." echo Invoke Make thus: "make srcdir=%XSRC%" +goto End + +:SmallEnv +echo Your environment is too small. Please enlarge it and run me again. + +:End +set XRSC= diff --git a/src/kmk/debug.h b/src/kmk/debug.h new file mode 100644 index 0000000..e423d90 --- /dev/null +++ b/src/kmk/debug.h @@ -0,0 +1,66 @@ +/* Debugging macros and interface. +Copyright (C) 1999-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#define DB_NONE (0x000) +#define DB_BASIC (0x001) +#define DB_VERBOSE (0x002) +#define DB_JOBS (0x004) +#define DB_IMPLICIT (0x008) +#define DB_MAKEFILES (0x100) +#ifdef KMK +# define DB_KMK (0x800) +#endif + +#define DB_ALL (0xfff) + +extern int db_level; + +#ifdef KMK + +/* Some extended info for -j and .NOTPARALLEL tracking. */ +extern unsigned int makelevel; +extern unsigned int job_slots; +extern unsigned int job_slots_used; + +#define DB_HDR() do { printf ("[%u:%u/%u]", makelevel, job_slots_used, job_slots); } while (0) + +#define ISDB(_l) ((_l)&db_level) + +#define DBS(_l,_x) do{ if(ISDB(_l)) {DB_HDR(); \ + print_spaces (depth); \ + printf _x; fflush (stdout);} }while(0) + +#define DBF(_l,_x) do{ if(ISDB(_l)) {DB_HDR(); \ + print_spaces (depth); \ + printf (_x, file->name); \ + fflush (stdout);} }while(0) + +#define DB(_l,_x) do{ if(ISDB(_l)) {DB_HDR(); printf _x; fflush (stdout);} }while(0) + +#else /* !KMK */ + +#define ISDB(_l) ((_l)&db_level) + +#define DBS(_l,_x) do{ if(ISDB(_l)) {print_spaces (depth); \ + printf _x; fflush (stdout);} }while(0) + +#define DBF(_l,_x) do{ if(ISDB(_l)) {print_spaces (depth); \ + printf (_x, file->name); \ + fflush (stdout);} }while(0) + +#define DB(_l,_x) do{ if(ISDB(_l)) {printf _x; fflush (stdout);} }while(0) + +#endif /* !KMK */ diff --git a/src/kmk/default.c b/src/kmk/default.c new file mode 100644 index 0000000..74b0cff --- /dev/null +++ b/src/kmk/default.c @@ -0,0 +1,774 @@ +/* Data base of default implicit rules for GNU Make. +Copyright (C) 1988-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#include "makeint.h" + +#include + +#include "filedef.h" +#include "variable.h" +#include "rule.h" +#include "dep.h" +#include "job.h" +#include "commands.h" + +/* Define GCC_IS_NATIVE if gcc is the native development environment on + your system (gcc/bison/flex vs cc/yacc/lex). */ +#if defined(__MSDOS__) || defined(__EMX__) +# define GCC_IS_NATIVE +#endif + + +/* This is the default list of suffixes for suffix rules. + '.s' must come last, so that a '.o' file will be made from + a '.c' or '.p' or ... file rather than from a .s file. */ + +static char default_suffixes[] +#ifndef CONFIG_NO_DEFAULT_SUFFIXES +#ifdef VMS + /* VMS should include all UNIX/POSIX + some VMS extensions */ + = ".out .exe .a .olb .hlb .tlb .mlb .ln .o .obj .c .cxx .cc .cpp .pas .p \ +.for .f .r .y .l .ym .yl .mar .s .ss .i .ii .mod .sym .def .h .info .dvi \ +.tex .texinfo .texi .txinfo .mem .hlp .brn .rnh .rno .rnt .rnx .w .ch .cweb \ +.web .com .sh .elc .el"; +#elif defined(__EMX__) + = ".out .a .ln .o .c .cc .C .cpp .p .f .F .m .r .y .l .ym .yl .s .S \ +.mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo \ +.w .ch .web .sh .elc .el .obj .exe .dll .lib"; +#else + = ".out .a .ln .o .c .cc .C .cpp .p .f .F .m .r .y .l .ym .yl .s .S \ +.mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo \ +.w .ch .web .sh .elc .el"; +#endif +#else /* CONFIG_NO_DEFAULT_SUFFIXES */ + = ""; +#endif /* CONFIG_NO_DEFAULT_SUFFIXES */ + +static struct pspec default_pattern_rules[] = + { +#ifndef CONFIG_NO_DEFAULT_PATTERN_RULES +#ifdef VMS + { "(%)", "%", + "@if f$$search(\"$@\") .eqs. \"\" then $(LIBRARY)/CREATE/" + "$(or " + "$(patsubst %,TEXT,$(filter %.tlb %.TLB,$@))," + "$(patsubst %,HELP,$(filter %.hlb %.HLB,$@))," + "$(patsubst %,MACRO,$(filter %.mlb %.MLB,$@))," + "$(and " + "$(patsubst %,SHARE,$(filter %.olb %.OLB,$@))," + "$(patsubst %,SHARE,$(filter %.exe %.EXE,$<)))," + "OBJECT)" + " $@\n" + "$(AR) $(ARFLAGS) $@ $<" }, + +#else + { "(%)", "%", + "$(AR) $(ARFLAGS) $@ $<" }, +#endif + /* The X.out rules are only in BSD's default set because + BSD Make has no null-suffix rules, so 'foo.out' and + 'foo' are the same thing. */ +#ifdef VMS + { "%.exe", "%", + "$(CP) $< $@" }, + +#endif + { "%.out", "%", + "@rm -f $@ \n cp $< $@" }, + + /* Syntax is "ctangle foo.w foo.ch foo.c". */ + { "%.c", "%.w %.ch", + "$(CTANGLE) $^ $@" }, + { "%.tex", "%.w %.ch", + "$(CWEAVE) $^ $@" }, +#endif /* !CONFIG_NO_DEFAULT_PATTERN_RULES */ + { 0, 0, 0 } + }; + +static struct pspec default_terminal_rules[] = + { +#ifndef CONFIG_NO_DEFAULT_TERMINAL_RULES +#ifdef VMS + + /* RCS. */ + { "%", "%$$5lv", /* Multinet style */ + "if f$$search(\"$@\") .nes. \"\" then +$(CHECKOUT,v)" }, + { "%", "[.$$rcs]%$$5lv", /* Multinet style */ + "if f$$search(\"$@\") .nes. \"\" then +$(CHECKOUT,v)" }, + { "%", "%_v", /* Normal style */ + "if f$$search(\"$@\") .nes. \"\" then +$(CHECKOUT,v)" }, + { "%", "[.rcs]%_v", /* Normal style */ + "if f$$search(\"$@\") .nes. \"\" then +$(CHECKOUT,v)" }, + + /* SCCS. */ + /* ain't no SCCS on vms */ + +#else + /* RCS. */ + { "%", "%,v", + "$(CHECKOUT,v)" }, + { "%", "RCS/%,v", + "$(CHECKOUT,v)" }, + { "%", "RCS/%", + "$(CHECKOUT,v)" }, + + /* SCCS. */ + { "%", "s.%", + "$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<" }, + { "%", "SCCS/s.%", + "$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<" }, +#endif /* !VMS */ +#endif /* !CONFIG_NO_DEFAULT_TERMINAL_RULES */ + { 0, 0, 0 } + }; + +static const char *default_suffix_rules[] = + { +#ifndef CONFIG_NO_DEFAULT_SUFFIX_RULES +#ifdef VMS + ".o", + "$(LINK.obj) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".obj", + "$(LINK.obj) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".s", + "$(LINK.s) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".S", + "$(LINK.S) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".c", + "$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".cc", + "$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".C", + "$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".cpp", + "$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".f", + "$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".m", + "$(LINK.m) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".p", + "$(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".F", + "$(LINK.F) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".r", + "$(LINK.r) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".mod", + "$(COMPILE.mod) -o $@ -e $@ $^", + + ".def.sym", + "$(COMPILE.def) -o $@ $<", + + ".sh", + "copy $< >$@", + + ".obj.exe", + "$(LINK.obj) $^ $(LOADLIBES) $(LDLIBS) $(CRT0) /exe=$@", + ".mar.exe", + "$(COMPILE.mar) $^ \n $(LINK.obj) $(subst .mar,.obj,$^) $(LOADLIBES) $(LDLIBS) $(CRT0) /exe=$@", + ".s.o", + "$(COMPILE.s) -o $@ $<", + ".s.exe", + "$(COMPILE.s) $^ \n $(LINK.obj) $(subst .s,.obj,$^) $(LOADLIBES) $(LDLIBS) $(CRT0) /exe=$@", + ".c.exe", + "$(COMPILE.c) $^ \n $(LINK.obj) $(subst .c,.obj,$^) $(LOADLIBES) $(LDLIBS) $(CRT0) /exe=$@", + ".cc.exe", +#ifdef GCC_IS_NATIVE + "$(COMPILE.cc) $^ \n $(LINK.obj) $(CXXSTARTUP),sys$$disk:[]$(subst .cc,.obj,$^) $(LOADLIBES) $(LXLIBS) $(LDLIBS) $(CXXRT0) /exe=$@", +#else + "$(COMPILE.cc) $^ \n $(CXXLINK.obj) $(subst .cc,.obj,$^) $(LOADLIBES) $(LXLIBS) $(LDLIBS) $(CXXRT0) /exe=$@", + ".cxx.exe", + "$(COMPILE.cxx) $^ \n $(CXXLINK.obj) $(subst .cxx,.obj,$^) $(LOADLIBES) $(LXLIBS) $(LDLIBS) $(CXXRT0) /exe=$@", +#endif + ".for.exe", + "$(COMPILE.for) $^ \n $(LINK.obj) $(subst .for,.obj,$^) $(LOADLIBES) $(LDLIBS) /exe=$@", + ".pas.exe", + "$(COMPILE.pas) $^ \n $(LINK.obj) $(subst .pas,.obj,$^) $(LOADLIBES) $(LDLIBS) /exe=$@", + + ".com", + "copy $< >$@", + + ".mar.obj", + "$(COMPILE.mar) /obj=$@ $<", + ".s.obj", + "$(COMPILE.s) /obj=$@ $<", + ".ss.obj", + "$(COMPILE.s) /obj=$@ $<", + ".c.i", + "$(COMPILE.c)/prep /list=$@ $<", + ".c.s", + "$(COMPILE.c)/noobj/machine /list=$@ $<", + ".i.s", + "$(COMPILE.c)/noprep/noobj/machine /list=$@ $<", + ".c.obj", + "$(COMPILE.c) /obj=$@ $<", + ".c.o", + "$(COMPILE.c) /obj=$@ $<", + ".cc.ii", + "$(COMPILE.cc)/prep /list=$@ $<", + ".cc.ss", + "$(COMPILE.cc)/noobj/machine /list=$@ $<", + ".ii.ss", + "$(COMPILE.cc)/noprep/noobj/machine /list=$@ $<", + ".cc.obj", + "$(COMPILE.cc) /obj=$@ $<", + ".cc.o", + "$(COMPILE.cc) /obj=$@ $<", + ".cxx.obj", + "$(COMPILE.cxx) /obj=$@ $<", + ".cxx.o", + "$(COMPILE.cxx) /obj=$@ $<", + ".for.obj", + "$(COMPILE.for) /obj=$@ $<", + ".for.o", + "$(COMPILE.for) /obj=$@ $<", + ".pas.obj", + "$(COMPILE.pas) /obj=$@ $<", + ".pas.o", + "$(COMPILE.pas) /obj=$@ $<", + + ".y.c", + "$(YACC.y) $< \n rename y_tab.c $@", + ".l.c", + "$(LEX.l) $< \n rename lexyy.c $@", + + ".texinfo.info", + "$(MAKEINFO) $<", + + ".tex.dvi", + "$(TEX) $<", + + ".cpp.o", + "$(COMPILE.cpp) $(OUTPUT_OPTION) $<", + ".f.o", + "$(COMPILE.f) $(OUTPUT_OPTION) $<", + ".m.o", + "$(COMPILE.m) $(OUTPUT_OPTION) $<", + ".p.o", + "$(COMPILE.p) $(OUTPUT_OPTION) $<", + ".r.o", + "$(COMPILE.r) $(OUTPUT_OPTION) $<", + ".mod.o", + "$(COMPILE.mod) -o $@ $<", + + ".c.ln", + "$(LINT.c) -C$* $<", + ".y.ln", + "$(YACC.y) $< \n rename y_tab.c $@", + + ".l.ln", + "@$(RM) $*.c\n $(LEX.l) $< > $*.c\n$(LINT.c) -i $*.c -o $@\n $(RM) $*.c", + +#else /* ! VMS */ + + ".o", + "$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".s", + "$(LINK.s) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".S", + "$(LINK.S) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".c", + "$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".cc", + "$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".C", + "$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".cpp", + "$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".f", + "$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".m", + "$(LINK.m) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".p", + "$(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".F", + "$(LINK.F) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".r", + "$(LINK.r) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".mod", + "$(COMPILE.mod) -o $@ -e $@ $^", + + ".def.sym", + "$(COMPILE.def) -o $@ $<", + + ".sh", + "cat $< >$@ \n chmod a+x $@", + + ".s.o", + "$(COMPILE.s) -o $@ $<", + ".S.o", + "$(COMPILE.S) -o $@ $<", + ".c.o", + "$(COMPILE.c) $(OUTPUT_OPTION) $<", + ".cc.o", + "$(COMPILE.cc) $(OUTPUT_OPTION) $<", + ".C.o", + "$(COMPILE.C) $(OUTPUT_OPTION) $<", + ".cpp.o", + "$(COMPILE.cpp) $(OUTPUT_OPTION) $<", + ".f.o", + "$(COMPILE.f) $(OUTPUT_OPTION) $<", + ".m.o", + "$(COMPILE.m) $(OUTPUT_OPTION) $<", + ".p.o", + "$(COMPILE.p) $(OUTPUT_OPTION) $<", + ".F.o", + "$(COMPILE.F) $(OUTPUT_OPTION) $<", + ".r.o", + "$(COMPILE.r) $(OUTPUT_OPTION) $<", + ".mod.o", + "$(COMPILE.mod) -o $@ $<", + + ".c.ln", + "$(LINT.c) -C$* $<", + ".y.ln", +#ifndef __MSDOS__ + "$(YACC.y) $< \n $(LINT.c) -C$* y.tab.c \n $(RM) y.tab.c", +#else + "$(YACC.y) $< \n $(LINT.c) -C$* y_tab.c \n $(RM) y_tab.c", +#endif + ".l.ln", + "@$(RM) $*.c\n $(LEX.l) $< > $*.c\n$(LINT.c) -i $*.c -o $@\n $(RM) $*.c", + + ".y.c", +#ifndef __MSDOS__ + "$(YACC.y) $< \n mv -f y.tab.c $@", +#else + "$(YACC.y) $< \n mv -f y_tab.c $@", +#endif + ".l.c", + "@$(RM) $@ \n $(LEX.l) $< > $@", + ".ym.m", + "$(YACC.m) $< \n mv -f y.tab.c $@", + ".lm.m", + "@$(RM) $@ \n $(LEX.m) $< > $@", + + ".F.f", + "$(PREPROCESS.F) $(OUTPUT_OPTION) $<", + ".r.f", + "$(PREPROCESS.r) $(OUTPUT_OPTION) $<", + + /* This might actually make lex.yy.c if there's no %R% directive in $*.l, + but in that case why were you trying to make $*.r anyway? */ + ".l.r", + "$(LEX.l) $< > $@ \n mv -f lex.yy.r $@", + + ".S.s", + "$(PREPROCESS.S) $< > $@", + + ".texinfo.info", + "$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@", + + ".texi.info", + "$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@", + + ".txinfo.info", + "$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@", + + ".tex.dvi", + "$(TEX) $<", + + ".texinfo.dvi", + "$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<", + + ".texi.dvi", + "$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<", + + ".txinfo.dvi", + "$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<", + + ".w.c", + "$(CTANGLE) $< - $@", /* The '-' says there is no '.ch' file. */ + + ".web.p", + "$(TANGLE) $<", + + ".w.tex", + "$(CWEAVE) $< - $@", /* The '-' says there is no '.ch' file. */ + + ".web.tex", + "$(WEAVE) $<", + +#endif /* !VMS */ +#endif /* !CONFIG_NO_DEFAULT_SUFFIX_RULES */ + 0, 0, + }; + +static const char *default_variables[] = + { +#ifndef CONFIG_NO_DEFAULT_VARIABLES +#ifdef VMS +#ifdef __ALPHA + "ARCH", "ALPHA", +#endif +#ifdef __ia64 + "ARCH", "IA64", +#endif +#ifdef __VAX + "ARCH", "VAX", +#endif + "AR", "library", + "LIBRARY", "library", + "ARFLAGS", "/replace", + "AS", "macro", + "MACRO", "macro", +#ifdef GCC_IS_NATIVE + "CC", "gcc", +#else + "CC", "cc", +#endif + "CD", "builtin_cd", + "ECHO", "builtin_echo", +#ifdef GCC_IS_NATIVE + "C++", "gcc/plus", + "CXX", "gcc/plus", +#else + "C++", "cxx", + "CXX", "cxx", +#ifndef __ia64 + "CXXLD", "cxxlink", + "CXXLINK", "cxxlink", +#else + /* CXXLINK is not used on VMS/IA64 */ + "CXXLD", "link", + "CXXLINK", "link", +#endif +#endif + "CO", "co", + "CPP", "$(CC) /preprocess_only", + "FC", "fortran", + /* System V uses these, so explicit rules using them should work. + However, there is no way to make implicit rules use them and FC. */ + "F77", "$(FC)", + "F77FLAGS", "$(FFLAGS)", + "LD", "link", + "LEX", "lex", + "PC", "pascal", + "YACC", "bison/yacc", + "YFLAGS", "/Define/Verbose", + "BISON", "bison", + "MAKEINFO", "makeinfo", + "TEX", "tex", + "TEXINDEX", "texindex", + + "RM", "delete/nolog", + + "CSTARTUP", "", +#ifdef GCC_IS_NATIVE + "CRT0", ",sys$$library:vaxcrtl.olb/lib,gnu_cc_library:crt0.obj", + "CXXSTARTUP", "gnu_cc_library:crtbegin.obj", + "CXXRT0", ",sys$$library:vaxcrtl.olb/lib,gnu_cc_library:crtend.obj,gnu_cc_library:gxx_main.obj", + "LXLIBS", ",gnu_cc_library:libstdcxx.olb/lib,gnu_cc_library:libgccplus.olb/lib", + "LDLIBS", ",gnu_cc_library:libgcc.olb/lib", +#else + "CRT0", "", + "CXXSTARTUP", "", + "CXXRT0", "", + "LXLIBS", "", + "LDLIBS", "", +#endif + + "LINK.o", "$(LD) $(LDFLAGS)", + "LINK.obj", "$(LD) $(LDFLAGS)", +#ifndef GCC_IS_NATIVE + "CXXLINK.obj", "$(CXXLD) $(LDFLAGS)", + "COMPILE.cxx", "$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", +#endif + "COMPILE.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", + "LINK.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", + "COMPILE.m", "$(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", + "LINK.m", "$(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", + "COMPILE.cc", "$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", + "COMPILE.C", "$(COMPILE.cc)", + "COMPILE.cpp", "$(COMPILE.cc)", + "LINK.C", "$(LINK.cc)", + "LINK.cpp", "$(LINK.cc)", + "YACC.y", "$(YACC) $(YFLAGS)", + "LEX.l", "$(LEX) $(LFLAGS)", + "YACC.m", "$(YACC) $(YFLAGS)", + "LEX.m", "$(LEX) $(LFLAGS) -t", + "COMPILE.for", "$(FC) $(FFLAGS) $(TARGET_ARCH)", + "COMPILE.f", "$(FC) $(FFLAGS) $(TARGET_ARCH) -c", + "LINK.f", "$(FC) $(FFLAGS) $(LDFLAGS) $(TARGET_ARCH)", + "COMPILE.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", + "LINK.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", + "COMPILE.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -c", + "LINK.r", "$(FC) $(FFLAGS) $(RFLAGS) $(LDFLAGS) $(TARGET_ARCH)", + "COMPILE.pas", "$(PC) $(PFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", + "COMPILE.def", "$(M2C) $(M2FLAGS) $(DEFFLAGS) $(TARGET_ARCH)", + "COMPILE.mod", "$(M2C) $(M2FLAGS) $(MODFLAGS) $(TARGET_ARCH)", + "COMPILE.p", "$(PC) $(PFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", + "LINK.p", "$(PC) $(PFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", + "COMPILE.mar", "$(MACRO) $(MACROFLAGS)", + "COMPILE.s", "$(AS) $(ASFLAGS) $(TARGET_MACH)", + "LINK.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_MACH)", + "COMPILE.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c", + "PREPROCESS.S", "$(CC) -E $(CPPFLAGS)", + "PREPROCESS.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -F", + "PREPROCESS.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -F", + "LINT.c", "$(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", + + "MV", "rename/new_version", + "CP", "copy", + ".LIBPATTERNS", "%.olb lib%.a", + +#else /* !VMS */ + + "AR", "ar", + "ARFLAGS", "rv", + "AS", "as", +#ifdef GCC_IS_NATIVE + "CC", "gcc", +# ifdef __MSDOS__ + "CXX", "gpp", /* g++ is an invalid name on MSDOS */ +# else + "CXX", "gcc", +# endif /* __MSDOS__ */ + "OBJC", "gcc", +#else + "CC", "cc", + "CXX", "g++", + "OBJC", "cc", +#endif + + /* This expands to $(CO) $(COFLAGS) $< $@ if $@ does not exist, + and to the empty string if $@ does exist. */ + "CHECKOUT,v", "+$(if $(wildcard $@),,$(CO) $(COFLAGS) $< $@)", + "CO", "co", + "COFLAGS", "", + + "CPP", "$(CC) -E", +#ifdef CRAY + "CF77PPFLAGS", "-P", + "CF77PP", "/lib/cpp", + "CFT", "cft77", + "CF", "cf77", + "FC", "$(CF)", +#else /* Not CRAY. */ +#ifdef _IBMR2 + "FC", "xlf", +#else +#ifdef __convex__ + "FC", "fc", +#else + "FC", "f77", +#endif /* __convex__ */ +#endif /* _IBMR2 */ + /* System V uses these, so explicit rules using them should work. + However, there is no way to make implicit rules use them and FC. */ + "F77", "$(FC)", + "F77FLAGS", "$(FFLAGS)", +#endif /* Cray. */ + "GET", SCCS_GET, + "LD", "ld", +#ifdef GCC_IS_NATIVE + "LEX", "flex", +#else + "LEX", "lex", +#endif + "LINT", "lint", + "M2C", "m2c", +#ifdef pyr + "PC", "pascal", +#else +#ifdef CRAY + "PC", "PASCAL", + "SEGLDR", "segldr", +#else + "PC", "pc", +#endif /* CRAY. */ +#endif /* pyr. */ +#ifdef GCC_IS_NATIVE + "YACC", "bison -y", +#else + "YACC", "yacc", /* Or "bison -y" */ +#endif + "MAKEINFO", "makeinfo", + "TEX", "tex", + "TEXI2DVI", "texi2dvi", + "WEAVE", "weave", + "CWEAVE", "cweave", + "TANGLE", "tangle", + "CTANGLE", "ctangle", + + "RM", "rm -f", + + "LINK.o", "$(CC) $(LDFLAGS) $(TARGET_ARCH)", + "COMPILE.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", + "LINK.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", + "COMPILE.m", "$(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", + "LINK.m", "$(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", + "COMPILE.cc", "$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", +#ifndef HAVE_CASE_INSENSITIVE_FS + /* On case-insensitive filesystems, treat *.C files as *.c files, + to avoid erroneously compiling C sources as C++, which will + probably fail. */ + "COMPILE.C", "$(COMPILE.cc)", +#else + "COMPILE.C", "$(COMPILE.c)", +#endif + "COMPILE.cpp", "$(COMPILE.cc)", + "LINK.cc", "$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", +#ifndef HAVE_CASE_INSENSITIVE_FS + "LINK.C", "$(LINK.cc)", +#else + "LINK.C", "$(LINK.c)", +#endif + "LINK.cpp", "$(LINK.cc)", + "YACC.y", "$(YACC) $(YFLAGS)", + "LEX.l", "$(LEX) $(LFLAGS) -t", + "YACC.m", "$(YACC) $(YFLAGS)", + "LEX.m", "$(LEX) $(LFLAGS) -t", + "COMPILE.f", "$(FC) $(FFLAGS) $(TARGET_ARCH) -c", + "LINK.f", "$(FC) $(FFLAGS) $(LDFLAGS) $(TARGET_ARCH)", + "COMPILE.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", + "LINK.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", + "COMPILE.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -c", + "LINK.r", "$(FC) $(FFLAGS) $(RFLAGS) $(LDFLAGS) $(TARGET_ARCH)", + "COMPILE.def", "$(M2C) $(M2FLAGS) $(DEFFLAGS) $(TARGET_ARCH)", + "COMPILE.mod", "$(M2C) $(M2FLAGS) $(MODFLAGS) $(TARGET_ARCH)", + "COMPILE.p", "$(PC) $(PFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", + "LINK.p", "$(PC) $(PFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", + "LINK.s", "$(CC) $(ASFLAGS) $(LDFLAGS) $(TARGET_MACH)", + "COMPILE.s", "$(AS) $(ASFLAGS) $(TARGET_MACH)", + "LINK.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_MACH)", + "COMPILE.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c", + "PREPROCESS.S", "$(CC) -E $(CPPFLAGS)", + "PREPROCESS.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -F", + "PREPROCESS.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -F", + "LINT.c", "$(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", + +#ifndef NO_MINUS_C_MINUS_O + "OUTPUT_OPTION", "-o $@", +#endif + +#ifdef SCCS_GET_MINUS_G + "SCCS_OUTPUT_OPTION", "-G$@", +#endif + +#if defined(_AMIGA) + ".LIBPATTERNS", "%.lib", +#elif defined(__MSDOS__) + ".LIBPATTERNS", "lib%.a $(DJDIR)/lib/lib%.a", +#elif defined(__APPLE__) + ".LIBPATTERNS", "lib%.dylib lib%.a", +#elif defined(__CYGWIN__) || defined(WINDOWS32) + ".LIBPATTERNS", "lib%.dll.a %.dll.a lib%.a %.lib lib%.dll %.dll", +#else + ".LIBPATTERNS", "lib%.so lib%.a", +#endif + +#endif /* !VMS */ +#endif /* !CONFIG_NO_DEFAULT_VARIABLES */ + /* Make this assignment to avoid undefined variable warnings. */ + "GNUMAKEFLAGS", "", + 0, 0 + }; + +/* Set up the default .SUFFIXES list. */ + +void +set_default_suffixes (void) +{ + suffix_file = enter_file (strcache_add (".SUFFIXES")); + suffix_file->builtin = 1; + + if (no_builtin_rules_flag) + define_variable_cname ("SUFFIXES", "", o_default, 0); + else + { + struct dep *d; + const char *p = default_suffixes; + suffix_file->deps = enter_prereqs (PARSE_SIMPLE_SEQ ((char **)&p, struct dep), + NULL); + for (d = suffix_file->deps; d; d = d->next) + d->file->builtin = 1; + + define_variable_cname ("SUFFIXES", default_suffixes, o_default, 0); + } +} + +/* Enter the default suffix rules as file rules. This used to be done in + install_default_implicit_rules, but that loses because we want the + suffix rules installed before reading makefiles, and the pattern rules + installed after. */ + +void +install_default_suffix_rules (void) +{ + const char **s; + + if (no_builtin_rules_flag) + return; + + for (s = default_suffix_rules; *s != 0; s += 2) + { + struct file *f = enter_file (strcache_add (s[0])); + /* This function should run before any makefile is parsed. */ + assert (f->cmds == 0); +#ifndef CONFIG_WITH_ALLOC_CACHES + f->cmds = xmalloc (sizeof (struct commands)); +#else + f->cmds = alloccache_alloc (&commands_cache); +#endif + f->cmds->fileinfo.filenm = 0; + f->cmds->commands = xstrdup (s[1]); + f->cmds->command_lines = 0; + f->cmds->recipe_prefix = RECIPEPREFIX_DEFAULT; +#ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS + f->cmds->refs = 1000; +#endif + f->builtin = 1; + } +} + + +/* Install the default pattern rules. */ + +void +install_default_implicit_rules (void) +{ + struct pspec *p; + + if (no_builtin_rules_flag) + return; + + for (p = default_pattern_rules; p->target != 0; ++p) + install_pattern_rule (p, 0); + + for (p = default_terminal_rules; p->target != 0; ++p) + install_pattern_rule (p, 1); +} + +void +define_default_variables (void) +{ + const char **s; + + if (no_builtin_variables_flag) + return; + + for (s = default_variables; *s != 0; s += 2) + define_variable (s[0], strlen (s[0]), s[1], o_default, 1); +} + +void +undefine_default_variables (void) +{ + const char **s; + + for (s = default_variables; *s != 0; s += 2) + undefine_variable_global (s[0], strlen (s[0]), o_default); +} diff --git a/src/kmk/dep.h b/src/kmk/dep.h new file mode 100644 index 0000000..d53e8ef --- /dev/null +++ b/src/kmk/dep.h @@ -0,0 +1,184 @@ +/* Definitions of dependency data structures for GNU Make. +Copyright (C) 1988-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + + +/* Structure used in chains of names, for parsing and globbing. */ + +#define NAMESEQ(_t) \ + _t *next; \ + const char *name + +struct nameseq + { + NAMESEQ (struct nameseq); + }; + +/* Flag bits for the second argument to 'read_makefile'. + These flags are saved in the 'flags' field of each + 'struct goaldep' in the chain returned by 'read_all_makefiles'. */ + +#define RM_NO_DEFAULT_GOAL (1 << 0) /* Do not set default goal. */ +#define RM_INCLUDED (1 << 1) /* Search makefile search path. */ +#define RM_DONTCARE (1 << 2) /* No error if it doesn't exist. */ +#define RM_NO_TILDE (1 << 3) /* Don't expand ~ in file name. */ +#define RM_NOFLAG 0 + +/* Structure representing one dependency of a file. + Each struct file's 'deps' points to a chain of these, through 'next'. + 'stem' is the stem for this dep line of static pattern rule or NULL. */ + +#ifndef CONFIG_WITH_INCLUDEDEP +#define DEP(_t) \ + NAMESEQ (_t); \ + struct file *file; \ + const char *stem; \ + unsigned short flags : 8; \ + unsigned short changed : 1; \ + unsigned short ignore_mtime : 1; \ + unsigned short staticpattern : 1; \ + unsigned short need_2nd_expansion : 1 +#else +# define DEP(_t) \ + NAMESEQ (_t); \ + struct file *file; \ + const char *stem; \ + unsigned short flags : 8; \ + unsigned short changed : 1; \ + unsigned short ignore_mtime : 1; \ + unsigned short staticpattern : 1; \ + unsigned short need_2nd_expansion : 1; \ + unsigned short includedep : 1 +#endif + +struct dep + { + DEP (struct dep); + }; + +/* Structure representing one goal. + The goals to be built constitute a chain of these, chained through 'next'. + 'stem' is not used, but it's simpler to include and ignore it. */ + +struct goaldep + { + DEP (struct goaldep); + unsigned short error; + floc floc; + }; + +/* Options for parsing lists of filenames. */ + +#define PARSEFS_NONE 0x0000 +#define PARSEFS_NOSTRIP 0x0001 +#define PARSEFS_NOAR 0x0002 +#define PARSEFS_NOGLOB 0x0004 +#define PARSEFS_EXISTS 0x0008 +#define PARSEFS_NOCACHE 0x0010 + +#ifndef CONFIG_WITH_ALLOC_CACHES +#define PARSE_FILE_SEQ(_s,_t,_c,_p,_f) \ + (_t *)parse_file_seq ((_s),sizeof (_t),(_c),(_p),(_f)) +#define PARSE_SIMPLE_SEQ(_s,_t) \ + (_t *)parse_file_seq ((_s),sizeof (_t),MAP_NUL,NULL,PARSEFS_NONE) +#else +# define PARSE_FILE_SEQ(_s,_t,_c,_p,_f) \ + (_t *)parse_file_seq ((_s),sizeof (_t),(_c),(_p),(_f), \ + &PARSE_FILE_SEQ_IGNORE_ ## _t ## _cache) +# define PARSE_SIMPLE_SEQ(_s,_t) \ + (_t *)parse_file_seq ((_s),sizeof (_t),MAP_NUL,NULL,PARSEFS_NONE, \ + &PARSE_FILE_SEQ_IGNORE_ ## _t ## _cache) +# define PARSE_FILE_SEQ_IGNORE_struct +#endif + + +#ifdef VMS +void *parse_file_seq (); +#else +void *parse_file_seq (char **stringp, unsigned int size, + int stopmap, const char *prefix, int flags + IF_WITH_ALLOC_CACHES_PARAM(struct alloccache *cache)); +#endif + +char *tilde_expand (const char *name); + +#ifndef NO_ARCHIVES +struct nameseq *ar_glob (const char *arname, const char *member_pattern, unsigned int size); +#endif + +#define dep_name(d) ((d)->name ? (d)->name : (d)->file->name) + +#ifndef CONFIG_WITH_ALLOC_CACHES + +#define alloc_seq_elt(_t) xcalloc (sizeof (_t)) +void free_ns_chain (struct nameseq *n); + +#if defined(MAKE_MAINTAINER_MODE) && defined(__GNUC__) +/* Use inline to get real type-checking. */ +#define SI static inline +SI struct nameseq *alloc_ns() { return alloc_seq_elt (struct nameseq); } +SI struct dep *alloc_dep() { return alloc_seq_elt (struct dep); } +SI struct goaldep *alloc_goaldep() { return alloc_seq_elt (struct goaldep); } + +SI void free_ns(struct nameseq *n) { free (n); } +SI void free_dep(struct dep *d) { free_ns ((struct nameseq *)d); } +SI void free_goaldep(struct goaldep *g) { free_dep ((struct dep *)g); } + +SI void free_dep_chain(struct dep *d) { free_ns_chain((struct nameseq *)d); } +SI void free_goal_chain(struct goaldep *g) { free_dep_chain((struct dep *)g); } +#else +# define alloc_ns() alloc_seq_elt (struct nameseq) +# define alloc_dep() alloc_seq_elt (struct dep) +# define alloc_goaldep() alloc_seq_elt (struct goaldep) + +# define free_ns(_n) free (_n) +# define free_dep(_d) free_ns (_d) +# define free_goaldep(_g) free_dep (_g) + +# define free_dep_chain(_d) free_ns_chain ((struct nameseq *)(_d)) +# define free_goal_chain(_g) free_ns_chain ((struct nameseq *)(_g)) +#endif + +#else /* CONFIG_WITH_ALLOC_CACHES */ + +# include + +K_INLINE struct nameseq *alloc_ns (void) { return (struct nameseq *)alloccache_calloc (&nameseq_cache); } +K_INLINE void free_ns (struct nameseq *n) { alloccache_free (&nameseq_cache, n); } +void free_ns_chain (struct nameseq *n); + +K_INLINE struct dep *alloc_dep (void) { return (struct dep *)alloccache_calloc (&dep_cache); } +K_INLINE void free_dep (struct dep *d) { alloccache_free (&dep_cache, d); } +void free_dep_chain (struct dep *d); + +K_INLINE struct goaldep *alloc_goaldep (void) { return (struct goaldep *)alloccache_calloc (&goaldep_cache); } +K_INLINE void free_goaldep (struct goaldep *g) { alloccache_free (&goaldep_cache, g); } +void free_goal_chain (struct goaldep *g); + +#endif /* CONFIG_WITH_ALLOC_CACHES */ + +struct dep *copy_dep_chain (const struct dep *d); + +struct goaldep *read_all_makefiles (const char **makefiles); +void eval_buffer (char *buffer, const floc *floc IF_WITH_VALUE_LENGTH(COMMA char *eos)); +enum update_status update_goal_chain (struct goaldep *goals); + +#ifdef CONFIG_WITH_INCLUDEDEP +/* incdep.c */ +enum incdep_op { incdep_read_it, incdep_queue, incdep_flush }; +void eval_include_dep (const char *name, floc *f, enum incdep_op op); +void incdep_flush_and_term (void); +#endif + diff --git a/src/kmk/dir-nt-bird.c b/src/kmk/dir-nt-bird.c new file mode 100644 index 0000000..d690751 --- /dev/null +++ b/src/kmk/dir-nt-bird.c @@ -0,0 +1,794 @@ +/* $Id: dir-nt-bird.c 3359 2020-06-05 16:17:17Z bird $ */ +/** @file + * Reimplementation of dir.c for NT using kFsCache. + * + * This should perform better on NT, especially on machines "infected" + * by antivirus programs. + */ + +/* + * Copyright (c) 2016 knut st. osmundsen + * + * This file is part of kBuild. + * + * kBuild is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * kBuild is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kBuild. If not, see + * + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include /* locking */ +#include "nt/kFsCache.h" +#include "makeint.h" +#if defined(KMK) && !defined(__OS2__) +# include "glob/glob.h" +#else +# include +#endif +#include +#include "kmkbuiltin.h" +#include "kmkbuiltin/err.h" + +#include "nt_fullpath.h" /* for the time being - will be implemented here later on. */ + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +/** User data key indicating that it's an impossible file to make. + * See file_impossible() and file_impossible_p(). */ +#define KMK_DIR_NT_IMPOSSIBLE_KEY (~(KUPTR)7) + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** + * glob directory stream. + */ +typedef struct KMKNTOPENDIR +{ + /** Reference to the directory. */ + PKFSDIR pDir; + /** Index of the next directory entry (child) to return. */ + KU32 idxNext; + /** The structure in which to return the directory entry. */ + struct dirent DirEnt; +} KMKNTOPENDIR; + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/** The cache.*/ +PKFSCACHE g_pFsCache = NULL; +/** Number of times dir_cache_invalid_missing was called. */ +static KU32 volatile g_cInvalidates = 0; +/** Set by dir_cache_volatile_dir to indicate that the user has marked the + * volatile parts of the file system with custom revisioning and we only need to + * flush these. This is very handy when using a separate output directory + * from the sources. */ +static KBOOL g_fFsCacheIsUsingCustomRevision = K_FALSE; +/** The ID of the main thread. We currently only let it access the cache. */ +static DWORD g_idMainThread = 0; + + +void hash_init_directories(void) +{ + g_idMainThread = GetCurrentThreadId(); + g_pFsCache = kFsCacheCreate(0); + if (g_pFsCache) + return; + fputs("kFsCacheCreate failed!", stderr); + exit(9); +} + + +/** + * Checks if @a pszName exists in directory @a pszDir. + * + * @returns 1 if it does, 0 if it doesn't. + * + * @param pszDir The directory. + * @param pszName The name. + * + * If empty string, just check if the directory exists. + * + * If NULL, just read the whole cache the directory into + * the cache (we always do that). + */ +int dir_file_exists_p(const char *pszDir, const char *pszName) +{ + int fRc = 0; + KFSLOOKUPERROR enmError; + PKFSOBJ pDirObj = kFsCacheLookupA(g_pFsCache, pszDir, &enmError); + assert(GetCurrentThreadId() == g_idMainThread); + if (pDirObj) + { + + if (pDirObj->bObjType == KFSOBJ_TYPE_DIR) + { + if (pszName != 0) + { + /* Empty filename is just checking out the directory. */ + if (*pszName == '\0') + fRc = 1; + else + { + PKFSOBJ pNameObj = kFsCacheLookupRelativeToDirA(g_pFsCache, (PKFSDIR)pDirObj, pszName, strlen(pszName), + 0/*fFlags*/, &enmError, NULL); + if (pNameObj) + { + fRc = pNameObj->bObjType == KFSOBJ_TYPE_MISSING; + kFsCacheObjRelease(g_pFsCache, pNameObj); + } + } + } + } + kFsCacheObjRelease(g_pFsCache, pDirObj); + } + return fRc; +} + + +/** + * Checks if a file exists. + * + * @returns 1 if it does exist, 0 if it doesn't. + * @param pszPath The path to check out. + * @note Multi-thread safe. + */ +int file_exists_p(const char *pszPath) +{ + int fRc; + KFSLOOKUPERROR enmError; + PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError); + if (pPathObj) + { + fRc = pPathObj->bObjType != KFSOBJ_TYPE_MISSING; + kFsCacheObjRelease(g_pFsCache, pPathObj); + } + else + fRc = 0; + return fRc; +} + + +/** + * Checks if a file exists and is a regular file, given a UTF-16 string. + * + * @returns 1 if it regular file, 0 if doesn't exist or isn't a file + * @param pwszPath The UTF-16 path to check out. + * @note Multi-thread safe. + */ +int utf16_regular_file_p(const wchar_t *pwszPath) +{ + int fRc; + KFSLOOKUPERROR enmError; + PKFSOBJ pPathObj = kFsCacheLookupW(g_pFsCache, pwszPath, &enmError); + if (pPathObj) + { + fRc = pPathObj->bObjType == KFSOBJ_TYPE_FILE; + kFsCacheObjRelease(g_pFsCache, pPathObj); + } + else + fRc = 0; + return fRc; +} + + +/** + * Just a way for vpath.c to get a correctly cased path, I think. + * + * @returns Directory path in string cache. + * @param pszDir The directory. + */ +const char *dir_name(const char *pszDir) +{ + char szTmp[MAX_PATH]; + assert(GetCurrentThreadId() == g_idMainThread); + nt_fullpath(pszDir, szTmp, sizeof(szTmp)); + return strcache_add(szTmp); +} + + +/** + * Makes future file_impossible_p calls return 1 for pszPath. + */ +void file_impossible(const char *pszPath) +{ + KFSLOOKUPERROR enmError; + PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError); + assert(GetCurrentThreadId() == g_idMainThread); + if (pPathObj) + { + kFsCacheObjAddUserData(g_pFsCache, pPathObj, KMK_DIR_NT_IMPOSSIBLE_KEY, sizeof(KFSUSERDATA)); + kFsCacheObjRelease(g_pFsCache, pPathObj); + } +} + +/** + * Makes future file_impossible_p calls return 1 for pszPath. + */ +int file_impossible_p(const char *pszPath) +{ + int fRc; + KFSLOOKUPERROR enmError; + PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError); + assert(GetCurrentThreadId() == g_idMainThread); + if (pPathObj) + { + fRc = kFsCacheObjGetUserData(g_pFsCache, pPathObj, KMK_DIR_NT_IMPOSSIBLE_KEY) != NULL; + kFsCacheObjRelease(g_pFsCache, pPathObj); + } + else + fRc = 0; + return fRc; +} + + +/** + * opendir for glob. + * + * @returns Pointer to DIR like handle, NULL if directory not found. + * @param pszDir The directory to enumerate. + */ +static __ptr_t dir_glob_opendir(const char *pszDir) +{ + KFSLOOKUPERROR enmError; + PKFSOBJ pDirObj = kFsCacheLookupA(g_pFsCache, pszDir, &enmError); + assert(GetCurrentThreadId() == g_idMainThread); + if (pDirObj) + { + if (pDirObj->bObjType == KFSOBJ_TYPE_DIR) + { + if (kFsCacheDirEnsurePopuplated(g_pFsCache, (PKFSDIR)pDirObj, NULL)) + { + KMKNTOPENDIR *pDir = xmalloc(sizeof(*pDir)); + pDir->pDir = (PKFSDIR)pDirObj; + pDir->idxNext = 0; + return pDir; + } + } + kFsCacheObjRelease(g_pFsCache, pDirObj); + } + return NULL; +} + + +/** + * readdir for glob. + * + * @returns Pointer to DIR like handle, NULL if directory not found. + * @param pDir Directory enum handle by dir_glob_opendir. + */ +static struct dirent *dir_glob_readdir(__ptr_t pvDir) +{ + KMKNTOPENDIR *pDir = (KMKNTOPENDIR *)pvDir; + KU32 const cChildren = pDir->pDir->cChildren; + assert(GetCurrentThreadId() == g_idMainThread); + while (pDir->idxNext < cChildren) + { + PKFSOBJ pEntry = pDir->pDir->papChildren[pDir->idxNext++]; + + /* Don't return missing objects. */ + if (pEntry->bObjType != KFSOBJ_TYPE_MISSING) + { + /* Copy the name that fits, trying to avoid names with spaces. + If neither fits, skip the name. */ + if ( pEntry->cchName < sizeof(pDir->DirEnt.d_name) + && ( pEntry->pszShortName == pEntry->pszName + || memchr(pEntry->pszName, ' ', pEntry->cchName) == NULL)) + { + pDir->DirEnt.d_namlen = pEntry->cchName; + memcpy(pDir->DirEnt.d_name, pEntry->pszName, pEntry->cchName + 1); + } + else if (pEntry->cchShortName < sizeof(pDir->DirEnt.d_name)) + { + pDir->DirEnt.d_namlen = pEntry->cchShortName; + memcpy(pDir->DirEnt.d_name, pEntry->pszShortName, pEntry->cchShortName + 1); + } + else + continue; + + pDir->DirEnt.d_reclen = offsetof(struct dirent, d_name) + pDir->DirEnt.d_namlen; + if (pEntry->bObjType == KFSOBJ_TYPE_DIR) + pDir->DirEnt.d_type = DT_DIR; + else if (pEntry->bObjType == KFSOBJ_TYPE_FILE) + pDir->DirEnt.d_type = DT_REG; + else + pDir->DirEnt.d_type = DT_UNKNOWN; + + return &pDir->DirEnt; + } + } + + /* + * Fake the '.' and '..' directories because they're not part of papChildren above. + */ + if (pDir->idxNext < cChildren + 2) + { + pDir->idxNext++; + pDir->DirEnt.d_type = DT_DIR; + pDir->DirEnt.d_namlen = pDir->idxNext - cChildren; + pDir->DirEnt.d_reclen = offsetof(struct dirent, d_name) + pDir->DirEnt.d_namlen; + pDir->DirEnt.d_name[0] = '.'; + pDir->DirEnt.d_name[1] = '.'; + pDir->DirEnt.d_name[pDir->DirEnt.d_namlen] = '\0'; + return &pDir->DirEnt; + } + + return NULL; +} + + +/** + * closedir for glob. + * + * @param pDir Directory enum handle by dir_glob_opendir. + */ +static void dir_glob_closedir(__ptr_t pvDir) +{ + KMKNTOPENDIR *pDir = (KMKNTOPENDIR *)pvDir; + assert(GetCurrentThreadId() == g_idMainThread); + kFsCacheObjRelease(g_pFsCache, &pDir->pDir->Obj); + pDir->pDir = NULL; + free(pDir); +} + + +/** + * stat for glob. + * + * @returns 0 on success, -1 + errno on failure. + * @param pszPath The path to stat. + * @param pStat Where to return the info. + */ +static int dir_glob_stat(const char *pszPath, struct stat *pStat) +{ + KFSLOOKUPERROR enmError; + PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError); + assert(GetCurrentThreadId() == g_idMainThread); +/** @todo follow symlinks vs. on symlink! */ + if (pPathObj) + { + if (pPathObj->bObjType != KFSOBJ_TYPE_MISSING) + { + kHlpAssert(pPathObj->fHaveStats); /* currently always true. */ + *pStat = pPathObj->Stats; + kFsCacheObjRelease(g_pFsCache, pPathObj); + return 0; + } + kFsCacheObjRelease(g_pFsCache, pPathObj); + } + errno = ENOENT; + return -1; +} + + +/** + * lstat for glob. + * + * @returns 0 on success, -1 + errno on failure. + * @param pszPath The path to stat. + * @param pStat Where to return the info. + */ +static int dir_glob_lstat(const char *pszPath, struct stat *pStat) +{ + KFSLOOKUPERROR enmError; + PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError); + assert(GetCurrentThreadId() == g_idMainThread); + if (pPathObj) + { + if (pPathObj->bObjType != KFSOBJ_TYPE_MISSING) + { + kHlpAssert(pPathObj->fHaveStats); /* currently always true. */ + *pStat = pPathObj->Stats; + kFsCacheObjRelease(g_pFsCache, pPathObj); + return 0; + } + kFsCacheObjRelease(g_pFsCache, pPathObj); + errno = ENOENT; + } + else + errno = enmError == KFSLOOKUPERROR_NOT_DIR + || enmError == KFSLOOKUPERROR_PATH_COMP_NOT_DIR + ? ENOTDIR : ENOENT; + + return -1; +} + + +/** + * Checks if @a pszDir exists and is a directory. + * + * @returns 1 if is directory, 0 if isn't or doesn't exists. + * @param pszDir The alleged directory. + */ +static int dir_globl_dir_exists_p(const char *pszDir) +{ + int fRc; + KFSLOOKUPERROR enmError; + PKFSOBJ pDirObj = kFsCacheLookupA(g_pFsCache, pszDir, &enmError); + assert(GetCurrentThreadId() == g_idMainThread); + if (pDirObj) + { + fRc = pDirObj->bObjType == KFSOBJ_TYPE_DIR; + kFsCacheObjRelease(g_pFsCache, pDirObj); + } + else + fRc = 0; + return fRc; + +} + + +/** + * Sets up pGlob with the necessary callbacks. + * + * @param pGlob Structure to populate. + */ +void dir_setup_glob(glob_t *pGlob) +{ + assert(GetCurrentThreadId() == g_idMainThread); + pGlob->gl_opendir = dir_glob_opendir; + pGlob->gl_readdir = dir_glob_readdir; + pGlob->gl_closedir = dir_glob_closedir; + pGlob->gl_stat = dir_glob_stat; +#ifdef __EMX__ /* The FreeBSD implementation actually uses gl_lstat!! */ + pGlob->gl_lstat = dir_glob_lstat; +#else + pGlob->gl_exists = file_exists_p; + pGlob->gl_isdir = dir_globl_dir_exists_p; +#endif +} + + +/** + * Print statitstics. + */ +void print_dir_stats(void) +{ + FILE *pOut = stdout; + KU32 cMisses; + + fputs("\n" + "# NT dir cache stats:\n", pOut); + fprintf(pOut, "# %u objects, taking up %u (%#x) bytes, avg %u bytes\n", + g_pFsCache->cObjects, g_pFsCache->cbObjects, g_pFsCache->cbObjects, g_pFsCache->cbObjects / g_pFsCache->cObjects); + fprintf(pOut, "# %u A path hashes, taking up %u (%#x) bytes, avg %u bytes, %u collision\n", + g_pFsCache->cAnsiPaths, g_pFsCache->cbAnsiPaths, g_pFsCache->cbAnsiPaths, + g_pFsCache->cbAnsiPaths / K_MAX(g_pFsCache->cAnsiPaths, 1), g_pFsCache->cAnsiPathCollisions); +#ifdef KFSCACHE_CFG_UTF16 + fprintf(pOut, "# %u W path hashes, taking up %u (%#x) bytes, avg %u bytes, %u collisions\n", + g_pFsCache->cUtf16Paths, g_pFsCache->cbUtf16Paths, g_pFsCache->cbUtf16Paths, + g_pFsCache->cbUtf16Paths / K_MAX(g_pFsCache->cUtf16Paths, 1), g_pFsCache->cUtf16PathCollisions); +#endif + fprintf(pOut, "# %u child hash tables, total of %u entries, %u children inserted, %u collisions\n", + g_pFsCache->cChildHashTabs, g_pFsCache->cChildHashEntriesTotal, + g_pFsCache->cChildHashed, g_pFsCache->cChildHashCollisions); + + cMisses = g_pFsCache->cLookups - g_pFsCache->cPathHashHits - g_pFsCache->cWalkHits; + fprintf(pOut, "# %u lookups: %u (%" KU64_PRI " %%) path hash hits, %u (%" KU64_PRI "%%) walks hits, %u (%" KU64_PRI "%%) misses\n", + g_pFsCache->cLookups, + g_pFsCache->cPathHashHits, g_pFsCache->cPathHashHits * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1), + g_pFsCache->cWalkHits, g_pFsCache->cWalkHits * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1), + cMisses, cMisses * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1)); + fprintf(pOut, "# %u child searches, %u (%" KU64_PRI "%%) hash hits\n", + g_pFsCache->cChildSearches, + g_pFsCache->cChildHashHits, g_pFsCache->cChildHashHits * (KU64)100 / K_MAX(g_pFsCache->cChildSearches, 1)); +} + + +void print_dir_data_base(void) +{ + /** @todo. */ + +} + + +/* duplicated in kWorker.c + * Note! Tries avoid to produce a result with spaces since they aren't supported by makefiles. */ +void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cbFull) +{ + KFSLOOKUPERROR enmError; + PKFSOBJ pPathObj; + + KFSCACHE_LOCK(g_pFsCache); /* let's start out being careful. */ + + pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError); + if (pPathObj) + { + KSIZE off = pPathObj->cchParent; + if (off > 0) + { + KSIZE offEnd = off + pPathObj->cchName; + if (offEnd < cbFull) + { + PKFSDIR pAncestor; + + pszFull[offEnd] = '\0'; + memcpy(&pszFull[off], pPathObj->pszName, pPathObj->cchName); + + for (pAncestor = pPathObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent) + { + kHlpAssert(off > 1); + kHlpAssert(pAncestor != NULL); + kHlpAssert(pAncestor->Obj.cchName > 0); + pszFull[--off] = '/'; +#ifdef KFSCACHE_CFG_SHORT_NAMES + if ( pAncestor->Obj.pszName == pAncestor->Obj.pszShortName + || memchr(pAncestor->Obj.pszName, ' ', pAncestor->Obj.cchName) == NULL) +#endif + { + off -= pAncestor->Obj.cchName; + kHlpAssert(pAncestor->Obj.cchParent == off); + memcpy(&pszFull[off], pAncestor->Obj.pszName, pAncestor->Obj.cchName); + } +#ifdef KFSCACHE_CFG_SHORT_NAMES + else + { + /* + * The long name constains a space, so use the alternative name instead. + * Most likely the alternative name differs in length, usually it's shorter, + * so we have to shift the part of the path we've already assembled + * accordingly. + */ + KSSIZE cchDelta = (KSSIZE)pAncestor->Obj.cchShortName - (KSSIZE)pAncestor->Obj.cchName; + if (cchDelta != 0) + { + if ((KSIZE)(offEnd + cchDelta) >= cbFull) + goto l_fallback; + memmove(&pszFull[off + cchDelta], &pszFull[off], offEnd + 1 - off); + off += cchDelta; + offEnd += cchDelta; + } + off -= pAncestor->Obj.cchShortName; + kHlpAssert(pAncestor->Obj.cchParent == off); + memcpy(&pszFull[off], pAncestor->Obj.pszShortName, pAncestor->Obj.cchShortName); + } +#endif + } + kFsCacheObjRelease(g_pFsCache, pPathObj); + KFSCACHE_UNLOCK(g_pFsCache); + return; + } + } + else + { + if ((size_t)pPathObj->cchName + 1 < cbFull) + { + /* Assume no spaces here. */ + memcpy(pszFull, pPathObj->pszName, pPathObj->cchName); + pszFull[pPathObj->cchName] = '/'; + pszFull[pPathObj->cchName + 1] = '\0'; + + kFsCacheObjRelease(g_pFsCache, pPathObj); + KFSCACHE_UNLOCK(g_pFsCache); + return; + } + } + + /* do fallback. */ +#ifdef KFSCACHE_CFG_SHORT_NAMES +l_fallback: +#endif + kHlpAssertFailed(); + kFsCacheObjRelease(g_pFsCache, pPathObj); + } + KFSCACHE_UNLOCK(g_pFsCache); + + nt_fullpath(pszPath, pszFull, cbFull); +} + + +/** + * Special stat call used by remake.c + * + * @returns 0 on success, -1 + errno on failure. + * @param pszPath The path to stat. + * @param pStat Where to return the mtime field only. + */ +int stat_only_mtime(const char *pszPath, struct stat *pStat) +{ + /* Currently a little expensive, so just hit the file system once the + jobs starts comming in. */ + assert(GetCurrentThreadId() == g_idMainThread); + if (g_cInvalidates == 0) + { + KFSLOOKUPERROR enmError; + PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError); + if (pPathObj) + { + if (pPathObj->bObjType != KFSOBJ_TYPE_MISSING) + { + kHlpAssert(pPathObj->fHaveStats); /* currently always true. */ + pStat->st_mtime = pPathObj->Stats.st_mtime; + kFsCacheObjRelease(g_pFsCache, pPathObj); + return 0; + } + + kFsCacheObjRelease(g_pFsCache, pPathObj); + errno = ENOENT; + } + else + errno = enmError == KFSLOOKUPERROR_NOT_DIR + || enmError == KFSLOOKUPERROR_PATH_COMP_NOT_DIR + ? ENOTDIR : ENOENT; + return -1; + } + return birdStatModTimeOnly(pszPath, &pStat->st_mtim, 1 /*fFollowLink*/); +} + +/** + * Do cache invalidation after a job completes. + */ +void dir_cache_invalid_after_job(void) +{ + assert(GetCurrentThreadId() == g_idMainThread); + g_cInvalidates++; + if (g_fFsCacheIsUsingCustomRevision) + kFsCacheInvalidateCustomBoth(g_pFsCache); + else + kFsCacheInvalidateAll(g_pFsCache); +} + +/** + * Invalidate the whole directory cache + * + * Used by $(dircache-ctl invalidate) + * @note Multi-thread safe. + */ +void dir_cache_invalid_all(void) +{ + g_cInvalidates++; + kFsCacheInvalidateAll(g_pFsCache); +} + +/** + * Invalidate the whole directory cache and closes all open handles. + * + * Used by $(dircache-ctl invalidate-and-close-dirs) + * @param including_root Also close the root directory. + * @note Multi-thread safe. + */ +void dir_cache_invalid_all_and_close_dirs(int including_root) +{ + g_cInvalidates++; + kFsCacheInvalidateAllAndCloseDirs(g_pFsCache, !!including_root); +} + +/** + * Invalidate missing bits of the directory cache. + * + * Used by $(dircache-ctl invalidate-missing) + * @note Multi-thread safe. + */ +void dir_cache_invalid_missing(void) +{ + g_cInvalidates++; + kFsCacheInvalidateAll(g_pFsCache); +} + +/** + * Invalidate the volatile bits of the directory cache. + * + * Used by $(dircache-ctl invalidate-missing) + * @note Multi-thread safe. + */ +void dir_cache_invalid_volatile(void) +{ + g_cInvalidates++; + if (g_fFsCacheIsUsingCustomRevision) + kFsCacheInvalidateCustomBoth(g_pFsCache); + else + kFsCacheInvalidateAll(g_pFsCache); +} + +/** + * Used by $(dircache-ctl ) to mark a directory subtree or file as volatile. + * + * The first call changes the rest of the cache to be considered non-volatile. + * + * @returns 0 on success, -1 on failure. + * @param pszDir The directory (or file for what that is worth). + */ +int dir_cache_volatile_dir(const char *pszDir) +{ + KFSLOOKUPERROR enmError; + PKFSOBJ pObj = kFsCacheLookupA(g_pFsCache, pszDir, &enmError); + assert(GetCurrentThreadId() == g_idMainThread); + if (pObj) + { + KBOOL fRc = kFsCacheSetupCustomRevisionForTree(g_pFsCache, pObj); + kFsCacheObjRelease(g_pFsCache, pObj); + if (fRc) + { + g_fFsCacheIsUsingCustomRevision = K_TRUE; + return 0; + } + OS(error, reading_file, "failed to mark '%s' as volatile", pszDir); + } + else + OS(error, reading_file, "failed to mark '%s' as volatile (not found)", pszDir); + return -1; +} + +/** + * Invalidates a deleted directory so the cache can close handles to it. + * + * Used by kmk_builtin_rm and kmk_builtin_rmdir. + * + * @returns 0 on success, -1 on failure. + * @param pszDir The directory to invalidate as deleted. + */ +int dir_cache_deleted_directory(const char *pszDir) +{ + assert(GetCurrentThreadId() == g_idMainThread); + if (kFsCacheInvalidateDeletedDirectoryA(g_pFsCache, pszDir)) + return 0; + return -1; +} + + +int kmk_builtin_dircache(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx) +{ + assert(GetCurrentThreadId() == g_idMainThread); + if (argc >= 2) + { + const char *pszCmd = argv[1]; + if (strcmp(pszCmd, "invalidate") == 0) + { + if (argc == 2) + { + dir_cache_invalid_all(); + return 0; + } + errx(pCtx, 2, "the 'invalidate' command takes no arguments!\n"); + } + else if (strcmp(pszCmd, "invalidate-missing") == 0) + { + if (argc == 2) + { + dir_cache_invalid_missing (); + return 0; + } + errx(pCtx, 2, "the 'invalidate-missing' command takes no arguments!\n"); + } + else if (strcmp(pszCmd, "volatile") == 0) + { + int i; + for (i = 2; i < argc; i++) + dir_cache_volatile_dir(argv[i]); + return 0; + } + else if (strcmp(pszCmd, "deleted") == 0) + { + int i; + for (i = 2; i < argc; i++) + dir_cache_deleted_directory(argv[i]); + return 0; + } + else + errx(pCtx, 2, "Invalid command '%s'!\n", pszCmd); + } + else + errx(pCtx, 2, "No command given!\n"); + + K_NOREF(envp); + return 2; +} + diff --git a/src/kmk/dir.c b/src/kmk/dir.c new file mode 100644 index 0000000..1709479 --- /dev/null +++ b/src/kmk/dir.c @@ -0,0 +1,1602 @@ +/* Directory hashing for GNU Make. +Copyright (C) 1988-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#include "makeint.h" +#include "hash.h" +#include "filedef.h" +#include "dep.h" + +#ifdef HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +# ifdef VMS +/* its prototype is in vmsdir.h, which is not needed for HAVE_DIRENT_H */ +const char *vmsify (const char *name, int type); +# endif +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +# ifdef HAVE_VMSDIR_H +# include "vmsdir.h" +# endif /* HAVE_VMSDIR_H */ +#endif +/* bird: FreeBSD + smbfs -> readdir() + EBADF */ +#ifdef __FreeBSD__ +# include +#endif +/* bird: end */ + +#ifdef CONFIG_WITH_STRCACHE2 +# include +#endif + +/* In GNU systems, defines this macro for us. */ +#ifdef _D_NAMLEN +# undef NAMLEN +# define NAMLEN(d) _D_NAMLEN(d) +#endif + +#if (defined (POSIX) || defined (VMS) || defined (WINDOWS32)) && !defined (__GNU_LIBRARY__) +/* Posix does not require that the d_ino field be present, and some + systems do not provide it. */ +# define REAL_DIR_ENTRY(dp) 1 +# define FAKE_DIR_ENTRY(dp) +#else +# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) +# define FAKE_DIR_ENTRY(dp) (dp->d_ino = 1) +#endif /* POSIX */ + +#ifdef __MSDOS__ +#include +#include + +/* If it's MSDOS that doesn't have _USE_LFN, disable LFN support. */ +#ifndef _USE_LFN +#define _USE_LFN 0 +#endif + +static const char * +dosify (const char *filename) +{ + static char dos_filename[14]; + char *df; + int i; + + if (filename == 0 || _USE_LFN) + return filename; + + /* FIXME: what about filenames which violate + 8+3 constraints, like "config.h.in", or ".emacs"? */ + if (strpbrk (filename, "\"*+,;<=>?[\\]|") != 0) + return filename; + + df = dos_filename; + + /* First, transform the name part. */ + for (i = 0; i < 8 && ! STOP_SET (*filename, MAP_DOT|MAP_NUL); ++i) + *df++ = tolower ((unsigned char)*filename++); + + /* Now skip to the next dot. */ + while (! STOP_SET (*filename, MAP_DOT|MAP_NUL)) + ++filename; + if (*filename != '\0') + { + *df++ = *filename++; + for (i = 0; i < 3 && ! STOP_SET (*filename, MAP_DOT|MAP_NUL); ++i) + *df++ = tolower ((unsigned char)*filename++); + } + + /* Look for more dots. */ + while (! STOP_SET (*filename, MAP_DOT|MAP_NUL)) + ++filename; + if (*filename == '.') + return filename; + *df = 0; + return dos_filename; +} +#endif /* __MSDOS__ */ + +#ifdef WINDOWS32 +#include +#include "pathstuff.h" +#endif + +#ifdef _AMIGA +#include +#endif + +#ifdef HAVE_CASE_INSENSITIVE_FS +static const char * +downcase (const char *filename) +{ + static PATH_VAR (new_filename); + char *df; + + if (filename == 0) + return 0; + + df = new_filename; + while (*filename != '\0') + { + *df++ = tolower ((unsigned char)*filename); + ++filename; + } + + *df = 0; + + return new_filename; +} +#endif /* HAVE_CASE_INSENSITIVE_FS */ + +#ifdef VMS + +static char * +downcase_inplace(char *filename) +{ + char *name; + name = filename; + while (*name != '\0') + { + *name = tolower ((unsigned char)*name); + ++name; + } + return filename; +} + +#ifndef _USE_STD_STAT +/* VMS 8.2 fixed the VMS stat output to have unique st_dev and st_ino + when _USE_STD_STAT is used on the compile line. + + Prior to _USE_STD_STAT support, the st_dev is a pointer to thread + static memory containing the device of the last filename looked up. + + Todo: find out if the ino_t still needs to be faked on a directory. + */ + +/* Define this if the older VMS_INO_T is needed */ +#define VMS_INO_T 1 + +static int +vms_hash (const char *name) +{ + int h = 0; + + while (*name) + { + unsigned char uc = *name; + int g; +#ifdef HAVE_CASE_INSENSITIVE_FS + h = (h << 4) + (isupper (uc) ? tolower (uc) : uc); +#else + h = (h << 4) + uc; +#endif + name++; + g = h & 0xf0000000; + if (g) + { + h = h ^ (g >> 24); + h = h ^ g; + } + } + return h; +} + +/* fake stat entry for a directory */ +static int +vmsstat_dir (const char *name, struct stat *st) +{ + char *s; + int h; + DIR *dir; + + dir = opendir (name); + if (dir == 0) + return -1; + closedir (dir); + s = strchr (name, ':'); /* find device */ + if (s) + { + /* to keep the compiler happy we said "const char *name", now we cheat */ + *s++ = 0; + st->st_dev = (char *)vms_hash (name); + h = vms_hash (s); + *(s-1) = ':'; + } + else + { + st->st_dev = 0; + h = vms_hash (name); + } + + st->st_ino[0] = h & 0xff; + st->st_ino[1] = h & 0xff00; + st->st_ino[2] = h >> 16; + + return 0; +} + +# define stat(__path, __sbuf) vmsstat_dir (__path, __sbuf) + +#endif /* _USE_STD_STAT */ +#endif /* VMS */ + +/* Hash table of directories. */ + +#ifndef DIRECTORY_BUCKETS +#ifdef KMK +# define DIRECTORY_BUCKETS 4096 +# else +# define DIRECTORY_BUCKETS 199 +# endif +#endif + +struct directory_contents + { + dev_t dev; /* Device and inode numbers of this dir. */ +#ifdef WINDOWS32 + /* Inode means nothing on WINDOWS32. Even file key information is + * unreliable because it is random per file open and undefined for remote + * filesystems. The most unique attribute I can come up with is the fully + * qualified name of the directory. Beware though, this is also + * unreliable. I'm open to suggestion on a better way to emulate inode. */ +# ifndef CONFIG_WITH_STRCACHE2 + char *path_key; +# else + char const *path_key; /* strcache'ed */ +# endif + time_t ctime; + time_t mtime; /* controls check for stale directory cache */ + int fs_flags; /* FS_FAT, FS_NTFS, ... */ +# define FS_FAT 0x1 +# define FS_NTFS 0x2 +# define FS_UNKNOWN 0x4 +# ifdef KMK + time_t last_updated; /**< The last time the directory was re-read. */ +# endif +#else +# ifdef VMS_INO_T + ino_t ino[3]; +# else + ino_t ino; +# endif +#endif /* WINDOWS32 */ + struct hash_table dirfiles; /* Files in this directory. */ + DIR *dirstream; /* Stream reading this directory. */ + }; + +static unsigned long +directory_contents_hash_1 (const void *key_0) +{ + const struct directory_contents *key = key_0; + unsigned long hash; + +#ifdef WINDOWS32 +# ifndef CONFIG_WITH_STRCACHE2 + hash = 0; + ISTRING_HASH_1 (key->path_key, hash); +# else /* CONFIG_WITH_STRCACHE2 */ + hash = strcache2_calc_ptr_hash (&file_strcache, key->path_key); +# endif /* CONFIG_WITH_STRCACHE2 */ + hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) key->ctime; +#else +# ifdef VMS_INO_T + hash = (((unsigned int) key->dev << 4) + ^ ((unsigned int) key->ino[0] + + (unsigned int) key->ino[1] + + (unsigned int) key->ino[2])); +# else + hash = ((unsigned int) key->dev << 4) ^ (unsigned int) key->ino; +# endif +#endif /* WINDOWS32 */ + return hash; +} + +static unsigned long +directory_contents_hash_2 (const void *key_0) +{ + const struct directory_contents *key = key_0; + unsigned long hash; + +#ifdef WINDOWS32 +# ifndef CONFIG_WITH_STRCACHE2 + hash = 0; + ISTRING_HASH_2 (key->path_key, hash); +# else /* CONFIG_WITH_STRCACHE2 */ + hash = strcache2_get_hash (&file_strcache, key->path_key); +# endif /* CONFIG_WITH_STRCACHE2 */ + hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ctime; +#else +# ifdef VMS_INO_T + hash = (((unsigned int) key->dev << 4) + ^ ~((unsigned int) key->ino[0] + + (unsigned int) key->ino[1] + + (unsigned int) key->ino[2])); +# else + hash = ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ino; +# endif +#endif /* WINDOWS32 */ + + return hash; +} + +/* Sometimes it's OK to use subtraction to get this value: + result = X - Y; + But, if we're not sure of the type of X and Y they may be too large for an + int (on a 64-bit system for example). So, use ?: instead. + See Savannah bug #15534. + + NOTE! This macro has side-effects! +*/ + +#define MAKECMP(_x,_y) ((_x)<(_y)?-1:((_x)==(_y)?0:1)) + +static int +directory_contents_hash_cmp (const void *xv, const void *yv) +{ + const struct directory_contents *x = xv; + const struct directory_contents *y = yv; + int result; + +#ifdef WINDOWS32 +# ifndef CONFIG_WITH_STRCACHE2 + ISTRING_COMPARE (x->path_key, y->path_key, result); + if (result) + return result; +# else /* CONFIG_WITH_STRCACHE2 */ + if (x->path_key != y->path_key) + return -1; +# endif /* CONFIG_WITH_STRCACHE2 */ + result = MAKECMP(x->ctime, y->ctime); + if (result) + return result; +#else +# ifdef VMS_INO_T + result = MAKECMP(x->ino[0], y->ino[0]); + if (result) + return result; + result = MAKECMP(x->ino[1], y->ino[1]); + if (result) + return result; + result = MAKECMP(x->ino[2], y->ino[2]); + if (result) + return result; +# else + result = MAKECMP(x->ino, y->ino); + if (result) + return result; +# endif +#endif /* WINDOWS32 */ + + return MAKECMP(x->dev, y->dev); +} + +/* Table of directory contents hashed by device and inode number. */ +static struct hash_table directory_contents; + +#ifdef CONFIG_WITH_ALLOC_CACHES +/* Allocation cache for directory contents. */ +struct alloccache directory_contents_cache; +#endif + +struct directory + { + const char *name; /* Name of the directory. */ + + /* The directory's contents. This data may be shared by several + entries in the hash table, which refer to the same directory + (identified uniquely by 'dev' and 'ino') under different names. */ + struct directory_contents *contents; + }; + +#ifndef CONFIG_WITH_STRCACHE2 +static unsigned long +directory_hash_1 (const void *key) +{ + return_ISTRING_HASH_1 (((const struct directory *) key)->name); +} + +static unsigned long +directory_hash_2 (const void *key) +{ + return_ISTRING_HASH_2 (((const struct directory *) key)->name); +} + +static int +directory_hash_cmp (const void *x, const void *y) +{ + return_ISTRING_COMPARE (((const struct directory *) x)->name, + ((const struct directory *) y)->name); +} +#endif /* !CONFIG_WITH_STRCACHE2 */ + +/* Table of directories hashed by name. */ +static struct hash_table directories; + +#ifdef CONFIG_WITH_ALLOC_CACHES +/* Allocation cache for directories. */ +struct alloccache directories_cache; +#endif + +/* Never have more than this many directories open at once. */ + +#define MAX_OPEN_DIRECTORIES 10 + +static unsigned int open_directories = 0; + + +/* Hash table of files in each directory. */ + +struct dirfile + { + const char *name; /* Name of the file. */ + size_t length; + short impossible; /* This file is impossible. */ + }; + +#ifndef CONFIG_WITH_STRCACHE2 +static unsigned long +dirfile_hash_1 (const void *key) +{ + return_ISTRING_HASH_1 (((struct dirfile const *) key)->name); +} + +static unsigned long +dirfile_hash_2 (const void *key) +{ + return_ISTRING_HASH_2 (((struct dirfile const *) key)->name); +} + +static int +dirfile_hash_cmp (const void *xv, const void *yv) +{ + const struct dirfile *x = xv; + const struct dirfile *y = yv; + int result = x->length - y->length; + if (result) + return result; + return_ISTRING_COMPARE (x->name, y->name); +} +#endif /* !CONFIG_WITH_STRCACHE2 */ + +#ifndef DIRFILE_BUCKETS +#define DIRFILE_BUCKETS 107 +#endif + +#ifdef CONFIG_WITH_ALLOC_CACHES +/* Allocation cache for dirfiles. */ +struct alloccache dirfile_cache; +#endif + + +static int dir_contents_file_exists_p (struct directory_contents *dir, + const char *filename); +static struct directory *find_directory (const char *name); + +/* Find the directory named NAME and return its 'struct directory'. */ + +static struct directory * +find_directory (const char *name) +{ + struct directory *dir; + struct directory **dir_slot; + struct directory dir_key; + +#ifndef CONFIG_WITH_STRCACHE2 + dir_key.name = name; + dir_slot = (struct directory **) hash_find_slot (&directories, &dir_key); +#else + const char *p = name + strlen (name); +# if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) + dir_key.name = strcache_add_len (downcase(name), p - name); +# else + dir_key.name = strcache_add_len (name, p - name); +# endif + dir_slot = (struct directory **) hash_find_slot_strcached (&directories, &dir_key); +#endif + dir = *dir_slot; + + if (HASH_VACANT (dir)) + { + /* The directory was not found. Create a new entry for it. */ +#ifndef CONFIG_WITH_STRCACHE2 + const char *p = name + strlen (name); +#endif + struct stat st; + int r; + +#ifndef CONFIG_WITH_ALLOC_CACHES + dir = xmalloc (sizeof (struct directory)); +#else + dir = alloccache_alloc (&directories_cache); +#endif +#ifndef CONFIG_WITH_STRCACHE2 +#if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) + /* Todo: Why is this only needed on VMS? */ + { + char *lname = downcase_inplace (xstrdup (name)); + dir->name = strcache_add_len (lname, p - name); + free (lname); + } +#else + dir->name = strcache_add_len (name, p - name); +#endif +#else /* CONFIG_WITH_STRCACHE2 */ + dir->name = dir_key.name; +#endif /* CONFIG_WITH_STRCACHE2 */ + hash_insert_at (&directories, dir, dir_slot); + /* The directory is not in the name hash table. + Find its device and inode numbers, and look it up by them. */ + +#if defined(WINDOWS32) + { + char tem[MAXPATHLEN], *tstart, *tend; + + /* Remove any trailing slashes. Windows32 stat fails even on + valid directories if they end in a slash. */ + memcpy (tem, name, p - name + 1); + tstart = tem; + if (tstart[1] == ':') + tstart += 2; + for (tend = tem + (p - name - 1); + tend > tstart && (*tend == '/' || *tend == '\\'); + tend--) + *tend = '\0'; + + r = stat (tem, &st); + } +#else + EINTRLOOP (r, stat (name, &st)); +#endif + + if (r < 0) + { + /* Couldn't stat the directory. Mark this by + setting the 'contents' member to a nil pointer. */ + dir->contents = 0; + } + else + { + /* Search the contents hash table; device and inode are the key. */ + +#ifdef WINDOWS32 + PATH_VAR (w32_fullpath); + char *w32_path; +#endif + struct directory_contents *dc; + struct directory_contents **dc_slot; + struct directory_contents dc_key; + + dc_key.dev = st.st_dev; +#ifdef WINDOWS32 + w32_path = unix_slashes_resolved (name, w32_fullpath, GET_PATH_MAX); +# ifndef CONFIG_WITH_STRCACHE2 + dc_key.path_key = w32_path; /* = w32ify (name, 1); - bird */ +# else /* CONFIG_WITH_STRCACHE2 */ + dc_key.path_key = strcache_add (w32_path); +# endif /* CONFIG_WITH_STRCACHE2 */ + dc_key.ctime = st.st_ctime; +#else +# ifdef VMS_INO_T + dc_key.ino[0] = st.st_ino[0]; + dc_key.ino[1] = st.st_ino[1]; + dc_key.ino[2] = st.st_ino[2]; +# else + dc_key.ino = st.st_ino; +# endif +#endif + dc_slot = (struct directory_contents **) hash_find_slot (&directory_contents, &dc_key); + dc = *dc_slot; + + if (HASH_VACANT (dc)) + { + /* Nope; this really is a directory we haven't seen before. */ +#ifdef WINDOWS32 + char fs_label[BUFSIZ]; + char fs_type[BUFSIZ]; + unsigned long fs_serno; + unsigned long fs_flags; + unsigned long fs_len; +#endif +#if defined(WINDOWS32) && defined(KMK) + static char s_last_volume[4]; + static int s_last_flags; +#endif + +#ifndef CONFIG_WITH_ALLOC_CACHES + dc = (struct directory_contents *) + xmalloc (sizeof (struct directory_contents)); +#else + dc = (struct directory_contents *) + alloccache_alloc (&directory_contents_cache); +#endif + + /* Enter it in the contents hash table. */ + dc->dev = st.st_dev; +#ifdef WINDOWS32 +# ifndef CONFIG_WITH_STRCACHE2 + dc->path_key = xstrdup (w32_path); +# else /* CONFIG_WITH_STRCACHE2 */ + dc->path_key = dc_key.path_key; +# endif /* CONFIG_WITH_STRCACHE2 */ + + dc->ctime = st.st_ctime; + dc->mtime = st.st_mtime; +# ifdef KMK + dc->last_updated = time(NULL); +# endif + + /* NTFS is the only WINDOWS32 filesystem that bumps mtime on a + directory when files are added/deleted from a directory. */ + w32_path[3] = '\0'; + +# ifdef KMK /* Need for speed: Cache the GetVolumeInformation result. */ + if ( s_last_volume[0] == w32_path[0] + && s_last_volume[1] == w32_path[1] + && s_last_volume[2] == w32_path[2] + && s_last_volume[3] == w32_path[3]) + dc->fs_flags = s_last_flags; + else + { +# endif + if (GetVolumeInformation (w32_path, fs_label, sizeof (fs_label), + &fs_serno, &fs_len, &fs_flags, fs_type, + sizeof (fs_type)) == FALSE) + dc->fs_flags = FS_UNKNOWN; + else if (!strcmp (fs_type, "FAT")) + dc->fs_flags = FS_FAT; + else if (!strcmp (fs_type, "NTFS")) + dc->fs_flags = FS_NTFS; + else + dc->fs_flags = FS_UNKNOWN; +# ifdef KMK + s_last_volume[0] = w32_path[0]; + s_last_volume[1] = w32_path[1]; + s_last_volume[2] = w32_path[2]; + s_last_volume[3] = w32_path[3]; + s_last_flags = dc->fs_flags; +# endif +#else +# ifdef VMS_INO_T + dc->ino[0] = st.st_ino[0]; + dc->ino[1] = st.st_ino[1]; + dc->ino[2] = st.st_ino[2]; +# else + dc->ino = st.st_ino; +# endif +#endif /* WINDOWS32 */ + hash_insert_at (&directory_contents, dc, dc_slot); + ENULLLOOP (dc->dirstream, opendir (name)); + if (dc->dirstream == 0) + /* Couldn't open the directory. Mark this by setting the + 'files' member to a nil pointer. */ + dc->dirfiles.ht_vec = 0; + else + { +#ifdef KMK + int buckets = st.st_nlink * 2; + if (buckets < DIRFILE_BUCKETS) + buckets = DIRFILE_BUCKETS; + hash_init_strcached (&dc->dirfiles, buckets, &file_strcache, + offsetof (struct dirfile, name)); +#else +# ifndef CONFIG_WITH_STRCACHE2 + hash_init (&dc->dirfiles, DIRFILE_BUCKETS, + dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp); +# else /* CONFIG_WITH_STRCACHE2 */ + hash_init_strcached (&dc->dirfiles, DIRFILE_BUCKETS, + &file_strcache, + offsetof (struct dirfile, name)); +# endif /* CONFIG_WITH_STRCACHE2 */ +#endif + ++open_directories; + if (open_directories == MAX_OPEN_DIRECTORIES) + /* We have too many directories open already. + Read the entire directory and then close it. */ + dir_contents_file_exists_p (dc, 0); + } + } + + /* Point the name-hashed entry for DIR at its contents data. */ + dir->contents = dc; + } + } + + return dir; +} + +/* Return 1 if the name FILENAME is entered in DIR's hash table. + FILENAME must contain no slashes. */ + +static int +dir_contents_file_exists_p (struct directory_contents *dir, + const char *filename) +{ + struct dirfile *df; + struct dirent *d; +#ifdef WINDOWS32 +# ifndef KMK + struct stat st; +# endif + int rehash = 0; +#endif +#ifdef KMK + int ret = 0; +#endif + + if (dir == 0 || dir->dirfiles.ht_vec == 0) + /* The directory could not be stat'd or opened. */ + return 0; + +#ifdef __MSDOS__ + filename = dosify (filename); +#endif + +#ifdef HAVE_CASE_INSENSITIVE_FS + filename = downcase (filename); +#endif + +#ifdef __EMX__ + if (filename != 0) + _fnlwr (filename); /* lower case for FAT drives */ +#endif + if (filename != 0) + { + struct dirfile dirfile_key; + + if (*filename == '\0') + { + /* Checking if the directory exists. */ + return 1; + } +#ifndef CONFIG_WITH_STRCACHE2 + dirfile_key.name = filename; + dirfile_key.length = strlen (filename); + df = hash_find_item (&dir->dirfiles, &dirfile_key); +#else /* CONFIG_WITH_STRCACHE2 */ + dirfile_key.length = strlen (filename); + dirfile_key.name = filename + = strcache_add_len (filename, dirfile_key.length); + df = hash_find_item_strcached (&dir->dirfiles, &dirfile_key); +#endif /* CONFIG_WITH_STRCACHE2 */ + if (df) + return !df->impossible; + } + + /* The file was not found in the hashed list. + Try to read the directory further. */ + + if (dir->dirstream == 0) + { +#if defined(WINDOWS32) && !defined(KMK) + /* + * Check to see if directory has changed since last read. FAT + * filesystems force a rehash always as mtime does not change + * on directories (ugh!). + */ +# ifdef KMK + if (dir->path_key && time(NULL) > dc->last_updated + 2) /* KMK: Only recheck every 2 seconds. */ +# else + if (dir->path_key) +# endif + { + if ((dir->fs_flags & FS_FAT) != 0) + { + dir->mtime = time ((time_t *) 0); + rehash = 1; + } +# ifdef KMK + else if ( birdStatModTimeOnly (dir->path_key, &st.st_mtim, 1) == 0 + && st.st_mtime > dir->mtime) +# else + else if (stat (dir->path_key, &st) == 0 && st.st_mtime > dir->mtime) +# endif + { + /* reset date stamp to show most recent re-process. */ + dir->mtime = st.st_mtime; + rehash = 1; + } + + + /* If it has been already read in, all done. */ + if (!rehash) + return 0; + + /* make sure directory can still be opened; if not return. */ + dir->dirstream = opendir (dir->path_key); + if (!dir->dirstream) + return 0; +# ifdef KMK + dc->last_updated = time(NULL); +# endif + } + else +#endif + /* The directory has been all read in. */ + return 0; + } + + while (1) + { + /* Enter the file in the hash table. */ + unsigned int len; + struct dirfile dirfile_key; + struct dirfile **dirfile_slot; + + ENULLLOOP (d, readdir (dir->dirstream)); + if (d == 0) + { +/* bird: Workaround for smbfs mounts returning EBADF at the end of the search. + To exactly determin the cause here, I should probably do some smbfs + tracing, but for now just ignoring the EBADF on seems to work. + (The smb server is 64-bit vista, btw.) */ +#if defined (__FreeBSD__) + struct statfs stfs; + int saved_errno = errno; + errno = 0; + if (saved_errno == EBADF + && !fstatfs (dirfd (dir->dirstream), &stfs) + && !(stfs.f_flags & MNT_LOCAL) + && !strcmp(stfs.f_fstypename, "smbfs")) + { + /*fprintf (stderr, "EBADF on remote fs! dirfd=%d errno=%d\n", + dirfd (dir->dirstream), errno);*/ + saved_errno = 0; + } + errno = saved_errno; +#endif +/* bird: end */ + if (errno) + pfatal_with_name ("INTERNAL: readdir"); + break; + } + +#if defined(VMS) && defined(HAVE_DIRENT_H) + /* In VMS we get file versions too, which have to be stripped off. + Some versions of VMS return versions on Unix files even when + the feature option to strip them is set. */ + { + char *p = strrchr (d->d_name, ';'); + if (p) + *p = '\0'; + } +#endif + if (!REAL_DIR_ENTRY (d)) + continue; + + len = NAMLEN (d); +#ifndef CONFIG_WITH_STRCACHE2 + dirfile_key.name = d->d_name; + dirfile_key.length = len; + dirfile_slot = (struct dirfile **) hash_find_slot (&dir->dirfiles, &dirfile_key); +#else +# if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) + dirfile_key.name = strcache_add_len (downcase(d->d_name), len); +# else + dirfile_key.name = strcache_add_len (d->d_name, len); +# endif + dirfile_key.length = len; + dirfile_slot = (struct dirfile **) hash_find_slot_strcached (&dir->dirfiles, &dirfile_key); +#endif +#ifdef WINDOWS32 + /* + * If re-reading a directory, don't cache files that have + * already been discovered. + */ + if (! rehash || HASH_VACANT (*dirfile_slot)) +#endif + { +#ifndef CONFIG_WITH_ALLOC_CACHES + df = xmalloc (sizeof (struct dirfile)); +#else + df = alloccache_alloc (&dirfile_cache); +#endif +#ifndef CONFIG_WITH_STRCACHE2 +#if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) + /* TODO: Why is this only needed on VMS? */ + df->name = strcache_add_len (downcase_inplace (d->d_name), len); +#else + df->name = strcache_add_len (d->d_name, len); +#endif +#else /* CONFIG_WITH_STRCACHE2 */ + df->name = dirfile_key.name; +#endif /* CONFIG_WITH_STRCACHE2 */ + df->length = len; + df->impossible = 0; + hash_insert_at (&dir->dirfiles, df, dirfile_slot); + } + /* Check if the name matches the one we're searching for. */ +#ifndef CONFIG_WITH_STRCACHE2 + if (filename != 0 && patheq (d->d_name, filename)) +#else + if (filename != 0 && dirfile_key.name == filename) +#endif +#ifdef KMK + ret = 1; /* Cache the whole dir. Prevents trouble on windows and os2 during 'rebuild'. */ +#else + return 1; +#endif + } + + /* If the directory has been completely read in, + close the stream and reset the pointer to nil. */ + if (d == 0) + { + --open_directories; + closedir (dir->dirstream); + dir->dirstream = 0; + } +#ifdef KMK + return ret; +#else + return 0; +#endif +} + +/* Return 1 if the name FILENAME in directory DIRNAME + is entered in the dir hash table. + FILENAME must contain no slashes. */ + +int +dir_file_exists_p (const char *dirname, const char *filename) +{ +#ifdef VMS + if ((filename != NULL) && (dirname != NULL)) + { + int want_vmsify; + want_vmsify = (strpbrk (dirname, ":<[") != NULL); + if (want_vmsify) + filename = vmsify (filename, 0); + } +#endif + return dir_contents_file_exists_p (find_directory (dirname)->contents, + filename); +} + +/* Return 1 if the file named NAME exists. */ + +int +file_exists_p (const char *name) +{ + const char *dirend; + const char *dirname; + const char *slash; + +#ifndef NO_ARCHIVES + if (ar_name (name)) + return ar_member_date (name) != (time_t) -1; +#endif + + dirend = strrchr (name, '/'); +#ifdef VMS + if (dirend == 0) + { + dirend = strrchr (name, ']'); + dirend == NULL ? dirend : dirend++; + } + if (dirend == 0) + { + dirend = strrchr (name, '>'); + dirend == NULL ? dirend : dirend++; + } + if (dirend == 0) + { + dirend = strrchr (name, ':'); + dirend == NULL ? dirend : dirend++; + } +#endif /* VMS */ +#ifdef HAVE_DOS_PATHS + /* Forward and backslashes might be mixed. We need the rightmost one. */ + { + const char *bslash = strrchr (name, '\\'); + if (!dirend || bslash > dirend) + dirend = bslash; + /* The case of "d:file". */ + if (!dirend && name[0] && name[1] == ':') + dirend = name + 1; + } +#endif /* HAVE_DOS_PATHS */ + if (dirend == 0) +#ifndef _AMIGA + return dir_file_exists_p (".", name); +#else /* !AMIGA */ + return dir_file_exists_p ("", name); +#endif /* AMIGA */ + + slash = dirend; + if (dirend == name) + dirname = "/"; + else + { + char *p; +#ifdef HAVE_DOS_PATHS + /* d:/ and d: are *very* different... */ + if (dirend < name + 3 && name[1] == ':' && + (*dirend == '/' || *dirend == '\\' || *dirend == ':')) + dirend++; +#endif + p = alloca (dirend - name + 1); + memcpy (p, name, dirend - name); + p[dirend - name] = '\0'; + dirname = p; + } +#ifdef VMS + if (*slash == '/') + slash++; +#else + slash++; +#endif + return dir_file_exists_p (dirname, slash); +} + +/* Mark FILENAME as 'impossible' for 'file_impossible_p'. + This means an attempt has been made to search for FILENAME + as an intermediate file, and it has failed. */ + +void +file_impossible (const char *filename) +{ + const char *dirend; + const char *p = filename; + struct directory *dir; + struct dirfile *new; + + dirend = strrchr (p, '/'); +#ifdef VMS + if (dirend == NULL) + { + dirend = strrchr (p, ']'); + dirend == NULL ? dirend : dirend++; + } + if (dirend == NULL) + { + dirend = strrchr (p, '>'); + dirend == NULL ? dirend : dirend++; + } + if (dirend == NULL) + { + dirend = strrchr (p, ':'); + dirend == NULL ? dirend : dirend++; + } +#endif +#ifdef HAVE_DOS_PATHS + /* Forward and backslashes might be mixed. We need the rightmost one. */ + { + const char *bslash = strrchr (p, '\\'); + if (!dirend || bslash > dirend) + dirend = bslash; + /* The case of "d:file". */ + if (!dirend && p[0] && p[1] == ':') + dirend = p + 1; + } +#endif /* HAVE_DOS_PATHS */ + if (dirend == 0) +#ifdef _AMIGA + dir = find_directory (""); +#else /* !AMIGA */ + dir = find_directory ("."); +#endif /* AMIGA */ + else + { + const char *dirname; + const char *slash = dirend; + if (dirend == p) + dirname = "/"; + else + { + char *cp; +#ifdef HAVE_DOS_PATHS + /* d:/ and d: are *very* different... */ + if (dirend < p + 3 && p[1] == ':' && + (*dirend == '/' || *dirend == '\\' || *dirend == ':')) + dirend++; +#endif + cp = alloca (dirend - p + 1); + memcpy (cp, p, dirend - p); + cp[dirend - p] = '\0'; + dirname = cp; + } + dir = find_directory (dirname); +#ifdef VMS + if (*slash == '/') + filename = p = slash + 1; + else + filename = p = slash; +#else + filename = p = slash + 1; +#endif + } + + if (dir->contents == 0) + /* The directory could not be stat'd. We allocate a contents + structure for it, but leave it out of the contents hash table. */ +#ifndef CONFIG_WITH_ALLOC_CACHES + dir->contents = xcalloc (sizeof (struct directory_contents)); +#else + dir->contents = alloccache_calloc (&directory_contents_cache); +#endif + + if (dir->contents->dirfiles.ht_vec == 0) + { +#ifndef CONFIG_WITH_STRCACHE2 + hash_init (&dir->contents->dirfiles, DIRFILE_BUCKETS, + dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp); +#else /* CONFIG_WITH_STRCACHE2 */ + hash_init_strcached (&dir->contents->dirfiles, DIRFILE_BUCKETS, + &file_strcache, offsetof (struct dirfile, name)); +#endif /* CONFIG_WITH_STRCACHE2 */ + } + + /* Make a new entry and put it in the table. */ + +#ifndef CONFIG_WITH_ALLOC_CACHES + new = xmalloc (sizeof (struct dirfile)); +#else + new = alloccache_alloc (&dirfile_cache); +#endif + new->length = strlen (filename); +#if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) + /* todo: Why is this only needed on VMS? */ + new->name = strcache_add_len (downcase (filename), new->length); +#else + new->name = strcache_add_len (filename, new->length); +#endif + new->impossible = 1; +#ifndef CONFIG_WITH_STRCACHE2 + hash_insert (&dir->contents->dirfiles, new); +#else /* CONFIG_WITH_STRCACHE2 */ + hash_insert_strcached (&dir->contents->dirfiles, new); +#endif /* CONFIG_WITH_STRCACHE2 */ +} + +/* Return nonzero if FILENAME has been marked impossible. */ + +int +file_impossible_p (const char *filename) +{ + const char *dirend; + struct directory_contents *dir; + struct dirfile *dirfile; + struct dirfile dirfile_key; +#ifdef VMS + int want_vmsify = 0; +#endif + + dirend = strrchr (filename, '/'); +#ifdef VMS + if (dirend == NULL) + { + want_vmsify = (strpbrk (filename, "]>:^") != NULL); + dirend = strrchr (filename, ']'); + } + if (dirend == NULL && want_vmsify) + dirend = strrchr (filename, '>'); + if (dirend == NULL && want_vmsify) + dirend = strrchr (filename, ':'); +#endif +#ifdef HAVE_DOS_PATHS + /* Forward and backslashes might be mixed. We need the rightmost one. */ + { + const char *bslash = strrchr (filename, '\\'); + if (!dirend || bslash > dirend) + dirend = bslash; + /* The case of "d:file". */ + if (!dirend && filename[0] && filename[1] == ':') + dirend = filename + 1; + } +#endif /* HAVE_DOS_PATHS */ + if (dirend == 0) +#ifdef _AMIGA + dir = find_directory ("")->contents; +#else /* !AMIGA */ + dir = find_directory (".")->contents; +#endif /* AMIGA */ + else + { + const char *dirname; + const char *slash = dirend; + if (dirend == filename) + dirname = "/"; + else + { + char *cp; +#ifdef HAVE_DOS_PATHS + /* d:/ and d: are *very* different... */ + if (dirend < filename + 3 && filename[1] == ':' && + (*dirend == '/' || *dirend == '\\' || *dirend == ':')) + dirend++; +#endif + cp = alloca (dirend - filename + 1); + memcpy (cp, filename, dirend - filename); + cp[dirend - filename] = '\0'; + dirname = cp; + } + dir = find_directory (dirname)->contents; +#ifdef VMS + if (*slash == '/') + filename = slash + 1; + else + filename = slash; +#else + filename = slash + 1; +#endif + } + + if (dir == 0 || dir->dirfiles.ht_vec == 0) + /* There are no files entered for this directory. */ + return 0; + +#ifdef __MSDOS__ + filename = dosify (filename); +#endif +#ifdef HAVE_CASE_INSENSITIVE_FS + filename = downcase (filename); +#endif +#ifdef VMS + if (want_vmsify) + filename = vmsify (filename, 1); +#endif + +#ifndef CONFIG_WITH_STRCACHE2 + dirfile_key.name = filename; + dirfile_key.length = strlen (filename); + dirfile = hash_find_item (&dir->dirfiles, &dirfile_key); +#else + dirfile_key.length = strlen (filename); + dirfile_key.name = strcache_add_len (filename, dirfile_key.length); + dirfile = hash_find_item_strcached (&dir->dirfiles, &dirfile_key); +#endif + if (dirfile) + return dirfile->impossible; + + return 0; +} + +/* Return the already allocated name in the + directory hash table that matches DIR. */ + +const char * +dir_name (const char *dir) +{ + return find_directory (dir)->name; +} + +/* Print the data base of directories. */ + +void +print_dir_data_base (void) +{ + unsigned int files; + unsigned int impossible; + struct directory **dir_slot; + struct directory **dir_end; + + puts (_("\n# Directories\n")); + + files = impossible = 0; + + dir_slot = (struct directory **) directories.ht_vec; + dir_end = dir_slot + directories.ht_size; + for ( ; dir_slot < dir_end; dir_slot++) + { + struct directory *dir = *dir_slot; + if (! HASH_VACANT (dir)) + { + if (dir->contents == 0) + printf (_("# %s: could not be stat'd.\n"), dir->name); + else if (dir->contents->dirfiles.ht_vec == 0) + { +#ifdef WINDOWS32 + printf (_("# %s (key %s, mtime %I64u): could not be opened.\n"), + dir->name, dir->contents->path_key, + (unsigned long long)dir->contents->mtime); +#else /* WINDOWS32 */ +#ifdef VMS_INO_T + printf (_("# %s (device %d, inode [%d,%d,%d]): could not be opened.\n"), + dir->name, dir->contents->dev, + dir->contents->ino[0], dir->contents->ino[1], + dir->contents->ino[2]); +#else + printf (_("# %s (device %ld, inode %ld): could not be opened.\n"), + dir->name, (long int) dir->contents->dev, + (long int) dir->contents->ino); +#endif +#endif /* WINDOWS32 */ + } + else + { + unsigned int f = 0; + unsigned int im = 0; + struct dirfile **files_slot; + struct dirfile **files_end; + + files_slot = (struct dirfile **) dir->contents->dirfiles.ht_vec; + files_end = files_slot + dir->contents->dirfiles.ht_size; + for ( ; files_slot < files_end; files_slot++) + { + struct dirfile *df = *files_slot; + if (! HASH_VACANT (df)) + { + if (df->impossible) + ++im; + else + ++f; + } + } +#ifdef WINDOWS32 + printf (_("# %s (key %s, mtime %I64u): "), + dir->name, dir->contents->path_key, + (unsigned long long)dir->contents->mtime); +#else /* WINDOWS32 */ +#ifdef VMS_INO_T + printf (_("# %s (device %d, inode [%d,%d,%d]): "), + dir->name, dir->contents->dev, + dir->contents->ino[0], dir->contents->ino[1], + dir->contents->ino[2]); +#else + printf (_("# %s (device %ld, inode %ld): "), + dir->name, + (long)dir->contents->dev, (long)dir->contents->ino); +#endif +#endif /* WINDOWS32 */ + if (f == 0) + fputs (_("No"), stdout); + else + printf ("%u", f); + fputs (_(" files, "), stdout); + if (im == 0) + fputs (_("no"), stdout); + else + printf ("%u", im); + fputs (_(" impossibilities"), stdout); + if (dir->contents->dirstream == 0) + puts ("."); + else + puts (_(" so far.")); + files += f; + impossible += im; +#ifdef KMK + fputs ("# ", stdout); + hash_print_stats (&dir->contents->dirfiles, stdout); + fputs ("\n", stdout); +#endif + } + } + } + + fputs ("\n# ", stdout); + if (files == 0) + fputs (_("No"), stdout); + else + printf ("%u", files); + fputs (_(" files, "), stdout); + if (impossible == 0) + fputs (_("no"), stdout); + else + printf ("%u", impossible); + printf (_(" impossibilities in %lu directories.\n"), directories.ht_fill); +#ifdef KMK + fputs ("# directories: ", stdout); + hash_print_stats (&directories, stdout); + fputs ("\n# directory_contents: ", stdout); + hash_print_stats (&directory_contents, stdout); + fputs ("\n", stdout); +#endif +} + +#ifdef CONFIG_WITH_PRINT_STATS_SWITCH +/* Print stats */ + +void print_dir_stats (void) +{ + /** @todo normal dir stats. */ +} +#endif + +/* Hooks for globbing. */ + +/* Structure describing state of iterating through a directory hash table. */ + +struct dirstream + { + struct directory_contents *contents; /* The directory being read. */ + struct dirfile **dirfile_slot; /* Current slot in table. */ + }; + +/* Forward declarations. */ +static __ptr_t open_dirstream (const char *); +static struct dirent *read_dirstream (__ptr_t); + +static __ptr_t +open_dirstream (const char *directory) +{ + struct dirstream *new; + struct directory *dir = find_directory (directory); + + if (dir->contents == 0 || dir->contents->dirfiles.ht_vec == 0) + /* DIR->contents is nil if the directory could not be stat'd. + DIR->contents->dirfiles is nil if it could not be opened. */ + return 0; + + /* Read all the contents of the directory now. There is no benefit + in being lazy, since glob will want to see every file anyway. */ + + dir_contents_file_exists_p (dir->contents, 0); + + new = xmalloc (sizeof (struct dirstream)); + new->contents = dir->contents; + new->dirfile_slot = (struct dirfile **) new->contents->dirfiles.ht_vec; + + return (__ptr_t) new; +} + +static struct dirent * +read_dirstream (__ptr_t stream) +{ + static char *buf; + static unsigned int bufsz; + + struct dirstream *const ds = (struct dirstream *) stream; + struct directory_contents *dc = ds->contents; + struct dirfile **dirfile_end = (struct dirfile **) dc->dirfiles.ht_vec + dc->dirfiles.ht_size; + + while (ds->dirfile_slot < dirfile_end) + { + struct dirfile *df = *ds->dirfile_slot++; + if (! HASH_VACANT (df) && !df->impossible) + { + /* The glob interface wants a 'struct dirent', so mock one up. */ + struct dirent *d; + unsigned int len = df->length + 1; + unsigned int sz = sizeof (*d) - sizeof (d->d_name) + len; + if (sz > bufsz) + { + bufsz *= 2; + if (sz > bufsz) + bufsz = sz; + buf = xrealloc (buf, bufsz); + } + d = (struct dirent *) buf; +#ifdef __MINGW32__ +# if __MINGW32_MAJOR_VERSION < 3 || (__MINGW32_MAJOR_VERSION == 3 && \ + __MINGW32_MINOR_VERSION == 0) + d->d_name = xmalloc (len); +# endif +#endif + FAKE_DIR_ENTRY (d); +#ifdef _DIRENT_HAVE_D_NAMLEN + d->d_namlen = len - 1; +#endif +#ifdef _DIRENT_HAVE_D_TYPE + d->d_type = DT_UNKNOWN; +#endif + memcpy (d->d_name, df->name, len); + return d; + } + } + + return 0; +} + +/* On 64 bit ReliantUNIX (5.44 and above) in LFS mode, stat() is actually a + * macro for stat64(). If stat is a macro, make a local wrapper function to + * invoke it. + * + * On MS-Windows, stat() "succeeds" for foo/bar/. where foo/bar is a + * regular file; fix that here. + */ +#if !defined(stat) && !defined(WINDOWS32) || defined(VMS) +# ifndef VMS +# ifndef HAVE_SYS_STAT_H +int stat (const char *path, struct stat *sbuf); +# endif +# else + /* We are done with the fake stat. Go back to the real stat */ +# ifdef stat +# undef stat +# endif +# endif +# define local_stat stat +#else +static int +local_stat (const char *path, struct stat *buf) +{ + int e; +#ifdef WINDOWS32 + size_t plen = strlen (path); + + /* Make sure the parent of "." exists and is a directory, not a + file. This is because 'stat' on Windows normalizes the argument + foo/. => foo without checking first that foo is a directory. */ + if (plen > 1 && path[plen - 1] == '.' + && (path[plen - 2] == '/' || path[plen - 2] == '\\')) + { + char parent[MAXPATHLEN]; + + strncpy (parent, path, plen - 2); + parent[plen - 2] = '\0'; + if (stat (parent, buf) < 0 || !_S_ISDIR (buf->st_mode)) + return -1; + } +#endif + + EINTRLOOP (e, stat (path, buf)); + return e; +} +#endif + +#ifdef KMK +static int dir_exists_p (const char *dirname) +{ + if (file_exists_p (dirname)) + { + struct directory *dir = find_directory (dirname); + if (dir != NULL && dir->contents && dir->contents->dirfiles.ht_vec != NULL) + return 1; + } + return 0; +} +#endif + +void +dir_setup_glob (glob_t *gl) +{ + gl->gl_opendir = open_dirstream; + gl->gl_readdir = read_dirstream; + gl->gl_closedir = free; + gl->gl_stat = local_stat; +#ifdef __EMX__ /* The FreeBSD implementation actually uses gl_lstat!! */ + gl->gl_lstat = local_stat; +#endif +#ifdef GLOB_WITH_EXTENDED_KMK_MEMBERS + gl->gl_exists = file_exists_p; + gl->gl_isdir = dir_exists_p; +#endif + /* We don't bother setting gl_lstat, since glob never calls it. + The slot is only there for compatibility with 4.4 BSD. */ +} + +void +hash_init_directories (void) +{ +#ifndef CONFIG_WITH_STRCACHE2 + hash_init (&directories, DIRECTORY_BUCKETS, + directory_hash_1, directory_hash_2, directory_hash_cmp); +#else /* CONFIG_WITH_STRCACHE2 */ + hash_init_strcached (&directories, DIRECTORY_BUCKETS, &file_strcache, + offsetof (struct directory, name)); +#endif /* CONFIG_WITH_STRCACHE2 */ + hash_init (&directory_contents, DIRECTORY_BUCKETS, + directory_contents_hash_1, directory_contents_hash_2, + directory_contents_hash_cmp); +#ifdef CONFIG_WITH_ALLOC_CACHES + alloccache_init (&directories_cache, sizeof (struct directory), + "directories", NULL, NULL); + alloccache_init (&directory_contents_cache, sizeof (struct directory_contents), + "directory_contents", NULL, NULL); + alloccache_init (&dirfile_cache, sizeof (struct dirfile), + "dirfile", NULL, NULL); +#endif /* CONFIG_WITH_ALLOC_CACHES */ +} + diff --git a/src/kmk/doc/.gitignore b/src/kmk/doc/.gitignore new file mode 100644 index 0000000..ca68d2d --- /dev/null +++ b/src/kmk/doc/.gitignore @@ -0,0 +1,22 @@ +manual/ +gendocs_template +fdl.texi +make-stds.texi +stamp-vti +version.texi +make.info* +make*.html +make.aux +make.cp +make.cps +make.dvi +make.fn +make.fns +make.ky +make.log +make.pdf +make.pg +make.ps +make.toc +make.tp +make.vr diff --git a/src/kmk/doc/Makefile.am b/src/kmk/doc/Makefile.am new file mode 100644 index 0000000..11aa4d4 --- /dev/null +++ b/src/kmk/doc/Makefile.am @@ -0,0 +1,24 @@ +# -*-Makefile-*-, or close enough +# Copyright (C) 2000-2016 Free Software Foundation, Inc. +# This file is part of GNU Make. +# +# GNU Make is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +TEXI2HTML = texi2html +TEXI2HTML_FLAGS = -split_chapter + +info_TEXINFOS = make.texi +make_TEXINFOS = fdl.texi make-stds.texi + +CLEANFILES = make*.html diff --git a/src/kmk/dosbuild.bat b/src/kmk/dosbuild.bat new file mode 100644 index 0000000..71e71e1 --- /dev/null +++ b/src/kmk/dosbuild.bat @@ -0,0 +1,65 @@ +@echo off +rem Copyright (C) 1998-2016 Free Software Foundation, Inc. +rem This file is part of GNU Make. +rem +rem GNU Make is free software; you can redistribute it and/or modify it under +rem the terms of the GNU General Public License as published by the Free +rem Software Foundation; either version 3 of the License, or (at your option) +rem any later version. +rem +rem GNU Make is distributed in the hope that it will be useful, but WITHOUT +rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for. +rem more details. +rem +rem You should have received a copy of the GNU General Public License along +rem with this program. If not, see . + +echo Building Make for MSDOS + +rem Echo ON so they will see what is going on. +@echo on +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g commands.c -o commands.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g output.c -o output.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g job.c -o job.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g dir.c -o dir.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g file.c -o file.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g misc.c -o misc.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g main.c -o main.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -DINCLUDEDIR=\"c:/djgpp/include\" -O2 -g read.c -o read.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -DLIBDIR=\"c:/djgpp/lib\" -O2 -g remake.c -o remake.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g rule.c -o rule.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g implicit.c -o implicit.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g default.c -o default.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g variable.c -o variable.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g expand.c -o expand.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g function.c -o function.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g vpath.c -o vpath.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g hash.c -o hash.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g strcache.c -o strcache.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g version.c -o version.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g ar.c -o ar.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g arscan.c -o arscan.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g signame.c -o signame.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g remote-stub.c -o remote-stub.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g getopt.c -o getopt.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g getopt1.c -o getopt1.o +@cd glob +@if exist libglob.a del libglob.a +gcc -I. -c -DHAVE_CONFIG_H -I.. -O2 -g glob.c -o glob.o +gcc -I. -c -DHAVE_CONFIG_H -I.. -O2 -g fnmatch.c -o fnmatch.o +ar rv libglob.a glob.o fnmatch.o +@echo off +cd .. +echo commands.o > respf.$$$ +for %%f in (job output dir file misc main read remake rule implicit default variable) do echo %%f.o >> respf.$$$ +for %%f in (expand function vpath hash strcache version ar arscan signame remote-stub getopt getopt1) do echo %%f.o >> respf.$$$ +echo glob/libglob.a >> respf.$$$ +rem gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g guile.c -o guile.o +rem echo guile.o >> respf.$$$ +@echo Linking... +@echo on +gcc -o make.new @respf.$$$ +@if exist make.exe echo Make.exe is now built! +@if not exist make.exe echo Make.exe build failed... +@if exist make.exe del respf.$$$ diff --git a/src/kmk/electric.c b/src/kmk/electric.c new file mode 100644 index 0000000..b033073 --- /dev/null +++ b/src/kmk/electric.c @@ -0,0 +1,220 @@ +/* $Id: electric.c 2798 2015-09-19 20:35:03Z bird $ */ +/** @file + * A simple electric heap implementation. + */ + +/* + * Copyright (c) 2007-2010 knut st. osmundsen + * + * This file is part of kBuild. + * + * kBuild is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * kBuild is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kBuild. If not, see + * + */ + +#ifdef ELECTRIC_HEAP + +# ifdef WINDOWS32 +# include +# else +# include +# include +# include +# endif +# include +# include +# include + + +# define FREED_ENTRIES 512 +static struct +{ + void *ptr; + unsigned aligned; +} freed[FREED_ENTRIES]; +static unsigned freed_head = 0; +static unsigned freed_tail = 0; + + +static void fatal_error (const char *msg) +{ +#ifdef _MSC_VER + fprintf (stderr, "electric heap error: %s\n", msg); + __debugbreak (); +#else + fprintf (stderr, "electric heap error: %s (errno=%d)\n", msg, errno); + __asm__ ("int3"); /* not portable... */ +#endif + abort (); + exit (1); +} + +static void free_it (void *ptr, unsigned aligned) +{ +# ifdef WINDOWS32 + if (!VirtualFree (ptr, 0, MEM_RELEASE)) + fatal_error ("VirtualFree failed"); +# else + if (munmap(ptr, aligned)) + fatal_error ("munmap failed"); +# endif +} + +/* Return 1 if something was freed, 0 otherwise. */ +static int free_up_some (void) +{ + if (freed_tail == freed_head) + return 0; + free_it (freed[freed_tail].ptr, freed[freed_tail].aligned); + freed[freed_tail].ptr = NULL; + freed[freed_tail].aligned = 0; + freed_tail = (freed_tail + 1) % FREED_ENTRIES; + return 1; +} + +static unsigned *get_hdr (void *ptr) +{ + if (((uintptr_t)ptr & 0xfff) < sizeof(unsigned)) + return (unsigned *)(((uintptr_t)ptr - 0x1000) & ~0xfff); + return (unsigned *)((uintptr_t)ptr & ~0xfff); +} + +void xfree (void *ptr) +{ + unsigned int size, aligned; + unsigned *hdr; +# ifdef WINDOWS32 + DWORD fFlags = PAGE_NOACCESS; +# endif + + if (!ptr) + return; + + hdr = get_hdr (ptr); + size = *hdr; + aligned = (size + 0x1fff + sizeof(unsigned)) & ~0xfff; +# ifdef WINDOWS32 + if (!VirtualProtect (hdr, aligned - 0x1000, fFlags, &fFlags)) + fatal_error ("failed to protect freed memory"); +# else + if (mprotect(hdr, aligned - 0x1000, PROT_NONE)) + fatal_error ("failed to protect freed memory"); +# endif + + freed[freed_head].ptr = hdr; + freed[freed_head].aligned = aligned; + if (((freed_head + 1) % FREED_ENTRIES) == freed_tail) + free_up_some(); + freed_head = (freed_head + 1) % FREED_ENTRIES; +} + +void * +xmalloc (unsigned int size) +{ + /* Make sure we don't allocate 0, for pre-ANSI libraries. */ + unsigned int aligned = (size + 0x1fff + sizeof(unsigned)) & ~0xfff; + unsigned *hdr; + unsigned i; + for (i = 0; i < FREED_ENTRIES; i++) + { +# ifdef WINDOWS32 + DWORD fFlags = PAGE_NOACCESS; + hdr = VirtualAlloc(NULL, aligned, MEM_COMMIT, PAGE_READWRITE); + if (hdr + && !VirtualProtect((char *)hdr + aligned - 0x1000, 0x1000, fFlags, &fFlags)) + fatal_error ("failed to set guard page protection"); +# else + hdr = mmap(NULL, aligned, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (hdr == MAP_FAILED) + hdr = 0; + if (hdr + && mprotect((char *)hdr + aligned - 0x1000, 0x1000, PROT_NONE)) + fatal_error ("failed to set guard page protection"); +# endif + if (hdr) + break; + if (!free_up_some ()) + break; + } + if (hdr == 0) + fatal_error ("virtual memory exhausted"); + + *hdr = size; +# if 0 + return hdr + 1; +# else + return (char *)hdr + aligned - 0x1000 - size; +# endif +} + + +void * +xcalloc (unsigned size) +{ + void *result; + result = xmalloc (size); + return memset (result, 0, size); +} + +void * +xrealloc (void *ptr, unsigned int size) +{ + void *result; + result = xmalloc (size); + if (ptr) + { + unsigned *hdr = get_hdr (ptr); + unsigned int oldsize = *hdr; + memcpy (result, ptr, oldsize >= size ? size : oldsize); + xfree (ptr); + } + return result; +} + +char * +xstrdup (const char *ptr) +{ + if (ptr) + { + size_t size = strlen (ptr) + 1; + char *result = xmalloc (size); + return memcpy (result, ptr, size); + } + return NULL; +} + +# ifdef __GNUC__ +void * +xmalloc_size_t (size_t size) +{ + return xmalloc(size); +} + +void * +xcalloc_size_t (size_t size, size_t items) +{ + return xcalloc(size * items); +} + +void * +xrealloc_size_t (void *ptr, size_t size) +{ + return xrealloc(ptr, size); +} +# endif /* __GNUC__ */ + +#else /* !ELECTRIC_HEAP */ +extern void electric_heap_keep_ansi_c_quiet (void); +#endif /* !ELECTRIC_HEAP */ + diff --git a/src/kmk/electric.h b/src/kmk/electric.h new file mode 100644 index 0000000..b655e7e --- /dev/null +++ b/src/kmk/electric.h @@ -0,0 +1,66 @@ +/* $Id: electric.h 3150 2018-03-15 18:18:03Z bird $ */ +/** @file + * A simple electric heap implementation, wrapper header. + */ + +/* + * Copyright (c) 2007-2010 knut st. osmundsen + * + * This file is part of kBuild. + * + * kBuild is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * kBuild is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kBuild. If not, see + * + */ + +#ifdef ELECTRIC_HEAP + +#include +#ifdef WINDOWS32 +# include +#endif +#include /* strdup */ + +void xfree (void *); +void *xcalloc (unsigned int); +void *xmalloc (unsigned int); +void *xrealloc (void *, unsigned int); +char *xstrdup (const char *); +#ifdef __GNUC__ +void *xmalloc_size_t (size_t size); +void *xcalloc_size_t (size_t size, size_t items); +void *xrealloc_size_t (void *ptr, size_t size); +#endif + + +#undef free +//#define free(a) xfree(a) +#define free xfree +#undef strdup +#define strdup(a) xstrdup(a) + +#undef calloc +#undef malloc +#undef realloc +#ifdef __GNUC__ +# define calloc(a,b) xcalloc_size_t(a,b) +# define malloc(a) xmalloc_size_t(a) +# define realloc(a,b) xrealloc_size_t(a,b) +#else +# define calloc(a,b) xcalloc((a) * (b)) +# define malloc(a) xmalloc(a) +# define realloc(a,b) xrealloc((a),(b)) +#endif + +#endif + diff --git a/src/kmk/example-spaces.kmk b/src/kmk/example-spaces.kmk new file mode 100644 index 0000000..7533002 --- /dev/null +++ b/src/kmk/example-spaces.kmk @@ -0,0 +1,175 @@ +# $Id: example-spaces.kmk 3316 2020-03-31 01:13:22Z bird $ +## @file +# kBuild - examples of GNU make filename quoting (escaping). +# + +# +# Copyright (c) 2020 knut st. osmundsen +# +# This file is part of kBuild. +# +# kBuild is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# kBuild is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with kBuild. If not, see +# +# + + +all: \ + phoney\ space\ \ 1 \ + phoney\ colon\:\ 2 \ + phoney\ hash\#\ 3 \ + phoney\ dollar$$\ 4 \ + phoney\ slash-space\\\ 5 \ + phoney\ slash-hash\\\#\ 6 \ + phoney\ slash-slash-hash\\\\\#\ 7 \ + phoney\ percent%\ 10 \ + phoney\ pipe\|\ 11 \ + phoney\ plus+\ 12 \ + all-trailing-slashes1 \ + all-trailing-slashes2 \ + all-trailing-slashes3 \ + all-trailing-spaces1 \ + all-trailing-spaces2 \ + all-trailing-spaces3 \ + all-trailing-spaces4 \ + phoney\ 19-target-trailing-space-with-padding\ ignore \ + phoney\ 20-target-trailing-space-with-newline-padding\ ignore \ + phoney\ 21-target-trailing-space-with-newline-padding-and-tail\ my-tail-21 + + +ignore: + +# +# Trailing slashes are complicated in dependency lists: +# + +# Variant #1: Must have a line-continutation to work if last in the list, but no extra escaping. +# This doesn't work: all-trailing-slashes1: phoney\ trailing-slash13\ +# This doesn't work: all-trailing-slashes1: phoney\ trailing-slash13\\ +all-trailing-slashes1: phoney\ trailing-slash13\ \ + +all-trailing-slashes2: phoney\ trailing-slash13b\ \ + \ + \ + \ + +# Variant #2: If there are more dependencies following it, we must escape the trailing slash +all-trailing-slashes3: \ + phoney\ trailing-slash14\\ \ + phoney\ space\ \ 1 # whatever + +# +# Trailing spaces only works if there is a target following on the same line. +# +all-trailing-spaces1: phoney\ 15-trailing-space\ phoney_simple + +# Note! No stripping spaces! Trailing space here that gets stripped instead of escaped. +all-trailing-spaces2: phoney\ 16-no-trailing-space\ + +all-trailing-spaces3: phoney\ 17-3x-escaped-newlines\ \ +\ +\ + becomes-single-space + +# Note! Must have a trailing space or comment. +all-trailing-spaces4: phoney\ 18-3x-escaped-trailing-spaces-no-newline\ \ \ # + + +# +# TODO +# + +#busted: phoney\ equal\=\ 8 \ +#impossible: phoney\ semi\;\ 9 \ + + +# +# The rules. +# + +phoney_simple: + +phoney\ space\ \ 1: + echo "#1: '$@'" + +phoney\ colon\:\ 2: + echo "#2: '$@'" + +phoney\ hash\#\ 3 : + echo "#3: '$@'" + +phoney\ dollar$$\ 4 : + echo "#4: '$@'" + +phoney\ slash-space\\\ 5: + echo "#5: '$@'" + +phoney\ slash-hash\\\#\ 6: + echo "#6: '$@'" + +phoney\ slash-slash-hash\\\\\#\ 7: + echo "#7: '$@'" + +## This is busted: +#phoney\ equal=\ 8: +# echo "#8: '$@'" + +## This seems impossible: +#phoney\ semi\;: +# echo "#9: '$@'" + +phoney\ percent\%\ 10: # Note! The percent is only escaped on the target side! + echo "#10: '$@'" + +phoney\ pipe|\ 11: # Note! The pipe is only escaped on the dependency list side! + echo "#11: '$@'" + +phoney\ plus+\ 12: + echo "#12: '$@'" + +phoney\ trailing-slash13\\: + echo "#13: '$@'" + +phoney\ trailing-slash13b\\: + echo "#13b: '$@'" + +phoney\ trailing-slash14\\: + echo "#14: '$@'" + +phoney\ 15-trailing-space\ : + echo "#15: '$@'" + +phoney\ 16-no-trailing-space\\: + echo "#16: '$@'" + +phoney\ 17-3x-escaped-newlines\ becomes-single-space: + echo "#17: '$@'" + +phoney\ 18-3x-escaped-trailing-spaces-no-newline\ \ \\: + echo "#18: '$@'" + +phoney\ 19-target-trailing-space-with-padding\ : + echo "#19: '$@'" + +phoney\ 20-target-trailing-space-with-newline-padding\ \ +\ +: + echo "#20: '$@'" + +phoney\ 21-target-trailing-space-with-newline-padding-and-tail\ \ +\ + \ + \ +my-tail-21: + echo "#21: '$@'" + diff --git a/src/kmk/expand.c b/src/kmk/expand.c new file mode 100644 index 0000000..e11a35c --- /dev/null +++ b/src/kmk/expand.c @@ -0,0 +1,1286 @@ +/* Variable expansion functions for GNU Make. +Copyright (C) 1988-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#include "makeint.h" + +#include + +#include "filedef.h" +#include "job.h" +#include "commands.h" +#include "variable.h" +#include "rule.h" +#ifdef CONFIG_WITH_COMPILER +# include "kmk_cc_exec.h" +#endif + +/* Initially, any errors reported when expanding strings will be reported + against the file where the error appears. */ +const floc **expanding_var = &reading_file; + +/* The next two describe the variable output buffer. + This buffer is used to hold the variable-expansion of a line of the + makefile. It is made bigger with realloc whenever it is too small. + variable_buffer_length is the size currently allocated. + variable_buffer is the address of the buffer. + + For efficiency, it's guaranteed that the buffer will always have + VARIABLE_BUFFER_ZONE extra bytes allocated. This allows you to add a few + extra chars without having to call a function. Note you should never use + these bytes unless you're _sure_ you have room (you know when the buffer + length was last checked. */ + +#define VARIABLE_BUFFER_ZONE 5 + +#ifndef KMK +static unsigned int variable_buffer_length; +#else +unsigned int variable_buffer_length; +#endif +char *variable_buffer; + + +#ifdef CONFIG_WITH_VALUE_LENGTH +struct recycled_buffer +{ + struct recycled_buffer *next; + unsigned int length; +}; +struct recycled_buffer *recycled_head; +#endif /* CONFIG_WITH_VALUE_LENGTH */ + + + +#ifndef KMK +/* Subroutine of variable_expand and friends: + The text to add is LENGTH chars starting at STRING to the variable_buffer. + The text is added to the buffer at PTR, and the updated pointer into + the buffer is returned as the value. Thus, the value returned by + each call to variable_buffer_output should be the first argument to + the following call. */ + +char * +variable_buffer_output (char *ptr, const char *string, unsigned int length) +{ + register unsigned int newlen = length + (ptr - variable_buffer); + + if ((newlen + VARIABLE_BUFFER_ZONE) > variable_buffer_length) + { + unsigned int offset = ptr - variable_buffer; + variable_buffer_length = (newlen + 100 > 2 * variable_buffer_length + ? newlen + 100 + : 2 * variable_buffer_length); + variable_buffer = xrealloc (variable_buffer, variable_buffer_length); + ptr = variable_buffer + offset; + } + + memcpy (ptr, string, length); + return ptr + length; +} +#endif + +/* Return a pointer to the beginning of the variable buffer. */ + +static char * +initialize_variable_output (void) +{ + /* If we don't have a variable output buffer yet, get one. */ + +#ifdef CONFIG_WITH_VALUE_LENGTH + if (variable_buffer == 0) + { + struct recycled_buffer *recycled = recycled_head; + if (recycled) + { + recycled_head = recycled->next; + variable_buffer_length = recycled->length; + variable_buffer = (char *)recycled; + } + else + { + variable_buffer_length = 384; + variable_buffer = xmalloc (variable_buffer_length); + } + variable_buffer[0] = '\0'; + } +#else /* CONFIG_WITH_VALUE_LENGTH */ + if (variable_buffer == 0) + { + variable_buffer_length = 200; + variable_buffer = xmalloc (variable_buffer_length); + variable_buffer[0] = '\0'; + } +#endif /* CONFIG_WITH_VALUE_LENGTH */ + + return variable_buffer; +} + +/* Recursively expand V. The returned string is malloc'd. */ + +static char *allocated_variable_append (const struct variable *v); + +char * +#ifndef CONFIG_WITH_VALUE_LENGTH +recursively_expand_for_file (struct variable *v, struct file *file) +#else +recursively_expand_for_file (struct variable *v, struct file *file, + unsigned int *value_lenp) +#endif +{ + char *value; + const floc *this_var; + const floc **saved_varp; + struct variable_set_list *save = 0; + int set_reading = 0; + + /* Don't install a new location if this location is empty. + This can happen for command-line variables, builtin variables, etc. */ + saved_varp = expanding_var; + if (v->fileinfo.filenm) + { + this_var = &v->fileinfo; + expanding_var = &this_var; + } + + /* If we have no other file-reading context, use the variable's context. */ + if (!reading_file) + { + set_reading = 1; + reading_file = &v->fileinfo; + } + + if (v->expanding) + { + if (!v->exp_count) + /* Expanding V causes infinite recursion. Lose. */ + OS (fatal, *expanding_var, + _("Recursive variable '%s' references itself (eventually)"), + v->name); + --v->exp_count; + } + + if (file) + { + save = current_variable_set_list; + current_variable_set_list = file->variables; + } + + v->expanding = 1; +#ifndef CONFIG_WITH_VALUE_LENGTH + if (v->append) + value = allocated_variable_append (v); + else + value = allocated_variable_expand (v->value); +#else /* CONFIG_WITH_VALUE_LENGTH */ + if (!v->append) + { + if (!IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR (v)) + value = allocated_variable_expand_2 (v->value, v->value_length, value_lenp); + else + { + unsigned int len = v->value_length; + value = xmalloc (len + 2); + memcpy (value, v->value, len + 1); + value[len + 1] = '\0'; /* Extra terminator like allocated_variable_expand_2 returns. Why? */ + if (value_lenp) + *value_lenp = len; + } + } + else + { + value = allocated_variable_append (v); + if (value_lenp) + *value_lenp = strlen (value); + } +#endif /* CONFIG_WITH_VALUE_LENGTH */ + v->expanding = 0; + + if (set_reading) + reading_file = 0; + + if (file) + current_variable_set_list = save; + + expanding_var = saved_varp; + + return value; +} + +#ifdef CONFIG_WITH_VALUE_LENGTH +/* Worker for reference_variable() and kmk_exec_* that expands the recursive + variable V. The main difference between this and + recursively_expand[_for_file] is that this worker avoids the temporary + buffer and outputs directly into the current variable buffer (O). */ +char * +reference_recursive_variable (char *o, struct variable *v) +{ + const floc *this_var; + const floc **saved_varp; + int set_reading = 0; + + /* Don't install a new location if this location is empty. + This can happen for command-line variables, builtin variables, etc. */ + saved_varp = expanding_var; + if (v->fileinfo.filenm) + { + this_var = &v->fileinfo; + expanding_var = &this_var; + } + + /* If we have no other file-reading context, use the variable's context. */ + if (!reading_file) + { + set_reading = 1; + reading_file = &v->fileinfo; + } + + if (v->expanding) + { + if (!v->exp_count) + /* Expanding V causes infinite recursion. Lose. */ + OS (fatal, *expanding_var, + _("Recursive variable `%s' references itself (eventually)"), + v->name); + --v->exp_count; + } + + v->expanding = 1; + if (!v->append) + { + /* Expand directly into the variable buffer. */ +# ifdef CONFIG_WITH_COMPILER + v->expand_count++; + if ( v->expandprog + || (v->expand_count == 3 && kmk_cc_compile_variable_for_expand (v)) ) + o = kmk_exec_expand_to_var_buf (v, o); + else + variable_expand_string_2 (o, v->value, v->value_length, &o); +# else + MAKE_STATS_2 (v->expand_count++); + variable_expand_string_2 (o, v->value, v->value_length, &o); +# endif + } + else + { + /* XXX: Feel free to optimize appending target variables as well. */ + char *value = allocated_variable_append (v); + unsigned int value_len = strlen (value); + o = variable_buffer_output (o, value, value_len); + free (value); + } + v->expanding = 0; + + if (set_reading) + reading_file = 0; + + expanding_var = saved_varp; + + return o; +} +#endif /* CONFIG_WITH_VALUE_LENGTH */ + +/* Expand a simple reference to variable NAME, which is LENGTH chars long. */ + +#ifdef MY_INLINE /* bird */ +MY_INLINE char * +#else +#if defined(__GNUC__) +__inline +#endif +static char * +#endif +reference_variable (char *o, const char *name, unsigned int length) +{ + struct variable *v; +#ifndef CONFIG_WITH_VALUE_LENGTH + char *value; +#endif + + v = lookup_variable (name, length); + + if (v == 0) + warn_undefined (name, length); + + /* If there's no variable by that name or it has no value, stop now. */ + if (v == 0 || (*v->value == '\0' && !v->append)) + return o; + +#ifdef CONFIG_WITH_VALUE_LENGTH + assert (v->value_length == strlen (v->value)); + if (!v->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR (v)) + o = variable_buffer_output (o, v->value, v->value_length); + else + o = reference_recursive_variable (o, v); +#else /* !CONFIG_WITH_VALUE_LENGTH */ + value = (v->recursive ? recursively_expand (v) : v->value); + + o = variable_buffer_output (o, value, strlen (value)); + + if (v->recursive) + free (value); +#endif /* !CONFIG_WITH_VALUE_LENGTH */ + + return o; +} + +#ifndef CONFIG_WITH_VALUE_LENGTH /* Only using variable_expand_string_2! */ +/* Scan STRING for variable references and expansion-function calls. Only + LENGTH bytes of STRING are actually scanned. If LENGTH is -1, scan until + a null byte is found. + + Write the results to LINE, which must point into 'variable_buffer'. If + LINE is NULL, start at the beginning of the buffer. + Return a pointer to LINE, or to the beginning of the buffer if LINE is + NULL. + */ +char * +variable_expand_string (char *line, const char *string, long length) +{ + struct variable *v; + const char *p, *p1; + char *save; + char *o; + unsigned int line_offset; + + if (!line) + line = initialize_variable_output (); + o = line; + line_offset = line - variable_buffer; + + if (length == 0) + { + variable_buffer_output (o, "", 1); + return (variable_buffer); + } + + /* We need a copy of STRING: due to eval, it's possible that it will get + freed as we process it (it might be the value of a variable that's reset + for example). Also having a nil-terminated string is handy. */ + save = length < 0 ? xstrdup (string) : xstrndup (string, length); + p = save; + + while (1) + { + /* Copy all following uninteresting chars all at once to the + variable output buffer, and skip them. Uninteresting chars end + at the next $ or the end of the input. */ + + p1 = strchr (p, '$'); + + o = variable_buffer_output (o, p, p1 != 0 ? (unsigned int)(p1 - p) : strlen (p) + 1); + + if (p1 == 0) + break; + p = p1 + 1; + + /* Dispatch on the char that follows the $. */ + + switch (*p) + { + case '$': + case '\0': + /* $$ or $ at the end of the string means output one $ to the + variable output buffer. */ + o = variable_buffer_output (o, p1, 1); + break; + + case '(': + case '{': + /* $(...) or ${...} is the general case of substitution. */ + { + char openparen = *p; + char closeparen = (openparen == '(') ? ')' : '}'; + const char *begp; + const char *beg = p + 1; + char *op; + char *abeg = NULL; + const char *end, *colon; + + op = o; + begp = p; + if (handle_function (&op, &begp)) + { + o = op; + p = begp; + break; + } + + /* Is there a variable reference inside the parens or braces? + If so, expand it before expanding the entire reference. */ + + end = strchr (beg, closeparen); + if (end == 0) + /* Unterminated variable reference. */ + O (fatal, *expanding_var, _("unterminated variable reference")); + p1 = lindex (beg, end, '$'); + if (p1 != 0) + { + /* BEG now points past the opening paren or brace. + Count parens or braces until it is matched. */ + int count = 0; + for (p = beg; *p != '\0'; ++p) + { + if (*p == openparen) + ++count; + else if (*p == closeparen && --count < 0) + break; + } + /* If COUNT is >= 0, there were unmatched opening parens + or braces, so we go to the simple case of a variable name + such as '$($(a)'. */ + if (count < 0) + { + abeg = expand_argument (beg, p); /* Expand the name. */ + beg = abeg; + end = strchr (beg, '\0'); + } + } + else + /* Advance P to the end of this reference. After we are + finished expanding this one, P will be incremented to + continue the scan. */ + p = end; + + /* This is not a reference to a built-in function and + any variable references inside are now expanded. + Is the resultant text a substitution reference? */ + + colon = lindex (beg, end, ':'); + if (colon) + { + /* This looks like a substitution reference: $(FOO:A=B). */ + const char *subst_beg = colon + 1; + const char *subst_end = lindex (subst_beg, end, '='); + if (subst_end == 0) + /* There is no = in sight. Punt on the substitution + reference and treat this as a variable name containing + a colon, in the code below. */ + colon = 0; + else + { + const char *replace_beg = subst_end + 1; + const char *replace_end = end; + + /* Extract the variable name before the colon + and look up that variable. */ + v = lookup_variable (beg, colon - beg); + if (v == 0) + warn_undefined (beg, colon - beg); + + /* If the variable is not empty, perform the + substitution. */ + if (v != 0 && *v->value != '\0') + { + char *pattern, *replace, *ppercent, *rpercent; + char *value = (v->recursive + ? recursively_expand (v) + : v->value); + + /* Copy the pattern and the replacement. Add in an + extra % at the beginning to use in case there + isn't one in the pattern. */ + pattern = alloca (subst_end - subst_beg + 2); + *(pattern++) = '%'; + memcpy (pattern, subst_beg, subst_end - subst_beg); + pattern[subst_end - subst_beg] = '\0'; + + replace = alloca (replace_end - replace_beg + 2); + *(replace++) = '%'; + memcpy (replace, replace_beg, + replace_end - replace_beg); + replace[replace_end - replace_beg] = '\0'; + + /* Look for %. Set the percent pointers properly + based on whether we find one or not. */ + ppercent = find_percent (pattern); + if (ppercent) + { + ++ppercent; + rpercent = find_percent (replace); + if (rpercent) + ++rpercent; + } + else + { + ppercent = pattern; + rpercent = replace; + --pattern; + --replace; + } + + o = patsubst_expand_pat (o, value, pattern, replace, + ppercent, rpercent); + + if (v->recursive) + free (value); + } + } + } + + if (colon == 0) + /* This is an ordinary variable reference. + Look up the value of the variable. */ + o = reference_variable (o, beg, end - beg); + + free (abeg); + } + break; + + default: + if (ISSPACE (p[-1])) + break; + + /* A $ followed by a random char is a variable reference: + $a is equivalent to $(a). */ + o = reference_variable (o, p, 1); + + break; + } + + if (*p == '\0') + break; + + ++p; + } + + free (save); + + variable_buffer_output (o, "", 1); + return (variable_buffer + line_offset); +} + +#else /* CONFIG_WITH_VALUE_LENGTH */ +/* Scan STRING for variable references and expansion-function calls. Only + LENGTH bytes of STRING are actually scanned. If LENGTH is -1, scan until + a null byte is found. + + Write the results to LINE, which must point into `variable_buffer'. If + LINE is NULL, start at the beginning of the buffer. + Return a pointer to LINE, or to the beginning of the buffer if LINE is + NULL. Set EOLP to point to the string terminator. + */ +char * +variable_expand_string_2 (char *line, const char *string, long length, char **eolp) +{ + struct variable *v; + const char *p, *p1, *eos; + char *o; + unsigned int line_offset; + + if (!line) + line = initialize_variable_output(); + o = line; + line_offset = line - variable_buffer; + + if (length < 0) + length = strlen (string); + else + MY_ASSERT_MSG (string + length == (p1 = memchr (string, '\0', length)) || !p1, ("len=%ld p1=%p %s\n", length, p1, line)); + + /* Simple 1: Emptry string. */ + + if (length == 0) + { + o = variable_buffer_output (o, "\0", 2); + *eolp = o - 2; + return (variable_buffer + line_offset); + } + + /* Simple 2: Nothing to expand. ~50% if the kBuild calls. */ + + p1 = (const char *)memchr (string, '$', length); + if (p1 == 0) + { + o = variable_buffer_output (o, string, length); + o = variable_buffer_output (o, "\0", 2); + *eolp = o - 2; + assert (strchr (variable_buffer + line_offset, '\0') == *eolp); + return (variable_buffer + line_offset); + } + + p = string; + eos = p + length; + + while (1) + { + /* Copy all following uninteresting chars all at once to the + variable output buffer, and skip them. Uninteresting chars end + at the next $ or the end of the input. */ + + o = variable_buffer_output (o, p, p1 != 0 ? (p1 - p) : (eos - p)); + + if (p1 == 0) + break; + p = p1 + 1; + + /* Dispatch on the char that follows the $. */ + + switch (*p) + { + case '$': + /* $$ seen means output one $ to the variable output buffer. */ + o = variable_buffer_output (o, p, 1); + break; + + case '(': + case '{': + /* $(...) or ${...} is the general case of substitution. */ + { + char openparen = *p; + char closeparen = (openparen == '(') ? ')' : '}'; + const char *begp; + const char *beg = p + 1; + char *op; + char *abeg = NULL; + unsigned int alen = 0; + const char *end, *colon; + + op = o; + begp = p; + end = may_be_function_name (p + 1, eos); + if ( end + && handle_function (&op, &begp, end, eos)) + { + o = op; + p = begp; + MY_ASSERT_MSG (!(p1 = memchr (variable_buffer + line_offset, '\0', o - (variable_buffer + line_offset))), + ("line=%p o/exp_end=%p act_end=%p\n", variable_buffer + line_offset, o, p1)); + break; + } + + /* Is there a variable reference inside the parens or braces? + If so, expand it before expanding the entire reference. */ + + end = memchr (beg, closeparen, eos - beg); + if (end == 0) + /* Unterminated variable reference. */ + O (fatal, *expanding_var, _("unterminated variable reference")); + p1 = lindex (beg, end, '$'); + if (p1 != 0) + { + /* BEG now points past the opening paren or brace. + Count parens or braces until it is matched. */ + int count = 0; + for (p = beg; p < eos; ++p) + { + if (*p == openparen) + ++count; + else if (*p == closeparen && --count < 0) + break; + } + /* If COUNT is >= 0, there were unmatched opening parens + or braces, so we go to the simple case of a variable name + such as `$($(a)'. */ + if (count < 0) + { + unsigned int len; + char saved; + + /* Expand the name. */ + saved = *p; + *(char *)p = '\0'; /* XXX: proove that this is safe! XXX2: shouldn't be necessary any longer! */ + abeg = allocated_variable_expand_3 (beg, p - beg, &len, &alen); + beg = abeg; + end = beg + len; + *(char *)p = saved; + } + } + else + /* Advance P to the end of this reference. After we are + finished expanding this one, P will be incremented to + continue the scan. */ + p = end; + + /* This is not a reference to a built-in function and + any variable references inside are now expanded. + Is the resultant text a substitution reference? */ + + colon = lindex (beg, end, ':'); + if (colon) + { + /* This looks like a substitution reference: $(FOO:A=B). */ + const char *subst_beg, *subst_end, *replace_beg, *replace_end; + + subst_beg = colon + 1; + subst_end = lindex (subst_beg, end, '='); + if (subst_end == 0) + /* There is no = in sight. Punt on the substitution + reference and treat this as a variable name containing + a colon, in the code below. */ + colon = 0; + else + { + replace_beg = subst_end + 1; + replace_end = end; + + /* Extract the variable name before the colon + and look up that variable. */ + v = lookup_variable (beg, colon - beg); + if (v == 0) + warn_undefined (beg, colon - beg); + + /* If the variable is not empty, perform the + substitution. */ + if (v != 0 && *v->value != '\0') + { + char *pattern, *replace, *ppercent, *rpercent; + char *value = (v->recursive + ? recursively_expand (v) + : v->value); + + /* Copy the pattern and the replacement. Add in an + extra % at the beginning to use in case there + isn't one in the pattern. */ + pattern = alloca (subst_end - subst_beg + 2); + *(pattern++) = '%'; + memcpy (pattern, subst_beg, subst_end - subst_beg); + pattern[subst_end - subst_beg] = '\0'; + + replace = alloca (replace_end - replace_beg + 2); + *(replace++) = '%'; + memcpy (replace, replace_beg, + replace_end - replace_beg); + replace[replace_end - replace_beg] = '\0'; + + /* Look for %. Set the percent pointers properly + based on whether we find one or not. */ + ppercent = find_percent (pattern); + if (ppercent) + { + ++ppercent; + rpercent = find_percent (replace); + if (rpercent) + ++rpercent; + } + else + { + ppercent = pattern; + rpercent = replace; + --pattern; + --replace; + } + + o = patsubst_expand_pat (o, value, pattern, replace, + ppercent, rpercent); + + if (v->recursive) + free (value); + } + } + } + + if (colon == 0) + /* This is an ordinary variable reference. + Look up the value of the variable. */ + o = reference_variable (o, beg, end - beg); + + if (abeg) + recycle_variable_buffer (abeg, alen); + } + break; + + case '\0': + assert (p == eos); + break; + + default: + if (ISBLANK (p[-1])) /* XXX: This looks incorrect, previous is '$' */ + break; + + /* A $ followed by a random char is a variable reference: + $a is equivalent to $(a). */ + o = reference_variable (o, p, 1); + + break; + } + + if (++p >= eos) + break; + p1 = memchr (p, '$', eos - p); + } + + o = variable_buffer_output (o, "\0", 2); /* KMK: compensate for the strlen + 1 that was removed above. */ + *eolp = o - 2; + MY_ASSERT_MSG (strchr (variable_buffer + line_offset, '\0') == *eolp, + ("expected=%d actual=%d\nlength=%ld string=%.*s\n", + (int)(*eolp - variable_buffer + line_offset), (int)strlen(variable_buffer + line_offset), + length, (int)length, string)); + return (variable_buffer + line_offset); +} +#endif /* CONFIG_WITH_VALUE_LENGTH */ + +/* Scan LINE for variable references and expansion-function calls. + Build in 'variable_buffer' the result of expanding the references and calls. + Return the address of the resulting string, which is null-terminated + and is valid only until the next time this function is called. */ + +char * +variable_expand (const char *line) +{ +#ifndef CONFIG_WITH_VALUE_LENGTH + return variable_expand_string (NULL, line, (long)-1); +#else /* CONFIG_WITH_VALUE_LENGTH */ + char *s; + + /* this function is abused a lot like this: variable_expand(""). */ + if (!*line) + { + s = variable_buffer_output (initialize_variable_output (), "\0", 2); + return s - 2; + } + return variable_expand_string_2 (NULL, line, (long)-1, &s); +#endif /* CONFIG_WITH_VALUE_LENGTH */ +} + +/* Expand an argument for an expansion function. + The text starting at STR and ending at END is variable-expanded + into a null-terminated string that is returned as the value. + This is done without clobbering 'variable_buffer' or the current + variable-expansion that is in progress. */ + +char * +expand_argument (const char *str, const char *end) +{ +#ifndef CONFIG_WITH_VALUE_LENGTH + char *tmp, *alloc = NULL; + char *r; +#endif + + if (str == end) + return xstrdup (""); + +#ifndef CONFIG_WITH_VALUE_LENGTH + if (!end || *end == '\0') + return allocated_variable_expand (str); + + if (end - str + 1 > 1000) + tmp = alloc = xmalloc (end - str + 1); + else + tmp = alloca (end - str + 1); + + memcpy (tmp, str, end - str); + tmp[end - str] = '\0'; + + r = allocated_variable_expand (tmp); + + free (alloc); + + return r; +#else /* CONFIG_WITH_VALUE_LENGTH */ + if (!end) + return allocated_variable_expand_2 (str, ~0U, NULL); + return allocated_variable_expand_2 (str, end - str, NULL); +#endif /* CONFIG_WITH_VALUE_LENGTH */ +} + +/* Expand LINE for FILE. Error messages refer to the file and line where + FILE's commands were found. Expansion uses FILE's variable set list. */ + +char * +variable_expand_for_file (const char *line, struct file *file) +{ + char *result; + struct variable_set_list *savev; + const floc *savef; + + if (file == 0) + return variable_expand (line); + + savev = current_variable_set_list; + current_variable_set_list = file->variables; + + savef = reading_file; + if (file->cmds && file->cmds->fileinfo.filenm) + reading_file = &file->cmds->fileinfo; + else + reading_file = 0; + + result = variable_expand (line); + + current_variable_set_list = savev; + reading_file = savef; + + return result; +} + +#if defined (CONFIG_WITH_VALUE_LENGTH) || defined (CONFIG_WITH_COMMANDS_FUNC) +/* Expand LINE for FILE. Error messages refer to the file and line where + FILE's commands were found. Expansion uses FILE's variable set list. + + Differs from variable_expand_for_file in that it takes a pointer to + where in the variable buffer to start outputting the expanded string, + and that it can returned the length of the string if you wish. */ + +char * +variable_expand_for_file_2 (char *o, const char *line, unsigned int length, + struct file *file, unsigned int *value_lenp) +{ + char *result; + struct variable_set_list *savev; + const floc *savef; + long len = length == ~0U ? (long)-1 : (long)length; + char *eol; + + if (!o) + o = initialize_variable_output(); + + if (file == 0) + result = variable_expand_string_2 (o, line, len, &eol); + else + { + savev = current_variable_set_list; + current_variable_set_list = file->variables; + + savef = reading_file; + if (file->cmds && file->cmds->fileinfo.filenm) + reading_file = &file->cmds->fileinfo; + else + reading_file = 0; + + result = variable_expand_string_2 (o, line, len, &eol); + + current_variable_set_list = savev; + reading_file = savef; + } + + if (value_lenp) + *value_lenp = eol - result; + + return result; +} + +#endif /* CONFIG_WITH_VALUE_LENGTH || CONFIG_WITH_COMMANDS_FUNC */ +/* Like allocated_variable_expand, but for += target-specific variables. + First recursively construct the variable value from its appended parts in + any upper variable sets. Then expand the resulting value. */ + +static char * +variable_append (const char *name, unsigned int length, + const struct variable_set_list *set, int local) +{ + const struct variable *v; + char *buf = 0; + /* If this set is local and the next is not a parent, then next is local. */ + int nextlocal = local && set->next_is_parent == 0; + + /* If there's nothing left to check, return the empty buffer. */ + if (!set) + return initialize_variable_output (); + + /* Try to find the variable in this variable set. */ + v = lookup_variable_in_set (name, length, set->set); + + /* If there isn't one, or this one is private, try the set above us. */ + if (!v || (!local && v->private_var)) + return variable_append (name, length, set->next, nextlocal); + + /* If this variable type is append, first get any upper values. + If not, initialize the buffer. */ + if (v->append) + buf = variable_append (name, length, set->next, nextlocal); + else + buf = initialize_variable_output (); + + /* Append this value to the buffer, and return it. + If we already have a value, first add a space. */ + if (buf > variable_buffer) + buf = variable_buffer_output (buf, " ", 1); +#ifdef CONFIG_WITH_VALUE_LENGTH + assert (v->value_length == strlen (v->value)); +#endif + + /* Either expand it or copy it, depending. */ + if (! v->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR (v)) +#ifdef CONFIG_WITH_VALUE_LENGTH + return variable_buffer_output (buf, v->value, v->value_length); +#else + return variable_buffer_output (buf, v->value, strlen (v->value)); +#endif + +#ifdef CONFIG_WITH_VALUE_LENGTH + variable_expand_string_2 (buf, v->value, v->value_length, &buf); + return buf; +#else + buf = variable_expand_string (buf, v->value, strlen (v->value)); + return (buf + strlen (buf)); +#endif +} + +#ifdef CONFIG_WITH_VALUE_LENGTH +/* Expands the specified string, appending it to the specified + variable value. */ +void +append_expanded_string_to_variable (struct variable *v, const char *value, + unsigned int value_len, int append) +{ + char *p = (char *) memchr (value, '$', value_len); + if (!p) + /* fast path */ + append_string_to_variable (v,value, value_len, append); + else if (value_len) + { + unsigned int off_dollar = p - (char *)value; + + /* Install a fresh variable buffer. */ + char *saved_buffer; + unsigned int saved_buffer_length; + install_variable_buffer (&saved_buffer, &saved_buffer_length); + + p = variable_buffer; + if (append || !v->value_length) + { + /* Copy the current value into it and append a space. */ + if (v->value_length) + { + p = variable_buffer_output (p, v->value, v->value_length); + p = variable_buffer_output (p, " ", 1); + } + + /* Append the assignment value. */ + p = variable_buffer_output (p, value, off_dollar); + variable_expand_string_2 (p, value + off_dollar, value_len - off_dollar, &p); + } + else + { + /* Expand the assignemnt value. */ + p = variable_buffer_output (p, value, off_dollar); + variable_expand_string_2 (p, value + off_dollar, value_len - off_dollar, &p); + + /* Append a space followed by the old value. */ + p = variable_buffer_output (p, " ", 1); + p = variable_buffer_output (p, v->value, v->value_length + 1) - 1; + } + + /* Replace the variable with the variable buffer. */ +#ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE + if (v->rdonly_val) + v->rdonly_val = 0; + else +#endif + free (v->value); + v->value = variable_buffer; + v->value_length = p - v->value; + v->value_alloc_len = variable_buffer_length; + VARIABLE_CHANGED(v); + + /* Restore the variable buffer, but without freeing the current. */ + variable_buffer = NULL; + restore_variable_buffer (saved_buffer, saved_buffer_length); + } + /* else: Drop empty strings. Use $(NO_SUCH_VARIABLE) if a space is wanted. */ +} +#endif /* CONFIG_WITH_VALUE_LENGTH */ + +static char * +allocated_variable_append (const struct variable *v) +{ + char *val; + + /* Construct the appended variable value. */ + + char *obuf = variable_buffer; + unsigned int olen = variable_buffer_length; + + variable_buffer = 0; + + assert ((unsigned int)v->length == strlen (v->name)); /* bird */ + val = variable_append (v->name, strlen (v->name), /** @todo optimize by using v->length! */ + current_variable_set_list, 1); + variable_buffer_output (val, "", 1); + val = variable_buffer; + + variable_buffer = obuf; + variable_buffer_length = olen; + + return val; +} + +/* Like variable_expand_for_file, but the returned string is malloc'd. + This function is called a lot. It wants to be efficient. */ + +char * +allocated_variable_expand_for_file (const char *line, struct file *file) +{ + char *value; + + char *obuf = variable_buffer; + unsigned int olen = variable_buffer_length; + + variable_buffer = 0; + + value = variable_expand_for_file (line, file); + + variable_buffer = obuf; + variable_buffer_length = olen; + + return value; +} + +#ifdef CONFIG_WITH_VALUE_LENGTH +/* Handle the most common case in allocated_variable_expand_for_file + specially and provide some additional string length features. */ + +char * +allocated_variable_expand_2 (const char *line, unsigned int length, + unsigned int *value_lenp) +{ + char *value; + char *obuf = variable_buffer; + unsigned int olen = variable_buffer_length; + long len = length == ~0U ? -1L : (long)length; + char *eol; + + variable_buffer = 0; + + value = variable_expand_string_2 (NULL, line, len, &eol); + if (value_lenp) + *value_lenp = eol - value; + + variable_buffer = obuf; + variable_buffer_length = olen; + + return value; +} + +/* Initially created for handling a special case for variable_expand_string2 + where the variable name is expanded and freed right afterwards. This + variant allows the variable_buffer to be recycled and thus avoid bothering + with a slow free implementation. (Darwin is horrible slow.) */ + +char * +allocated_variable_expand_3 (const char *line, unsigned int length, + unsigned int *value_lenp, + unsigned int *buffer_lengthp) +{ + char *obuf = variable_buffer; + unsigned int olen = variable_buffer_length; + long len = (long)length; + char *value; + char *eol; + + variable_buffer = 0; + + value = variable_expand_string_2 (NULL, line, len, &eol); + if (value_lenp) + *value_lenp = eol - value; + *buffer_lengthp = variable_buffer_length; + + variable_buffer = obuf; + variable_buffer_length = olen; + + return value; +} + +/* recycle a buffer. */ + +void +recycle_variable_buffer (char *buffer, unsigned int length) +{ + struct recycled_buffer *recycled = (struct recycled_buffer *)buffer; + + assert (!(length & 31)); + assert (length >= 384); + recycled->length = length; + recycled->next = recycled_head; + recycled_head = recycled; +} + +#endif /* CONFIG_WITH_VALUE_LENGTH */ + +/* Install a new variable_buffer context, returning the current one for + safe-keeping. */ + +void +install_variable_buffer (char **bufp, unsigned int *lenp) +{ + *bufp = variable_buffer; + *lenp = variable_buffer_length; + + variable_buffer = 0; + initialize_variable_output (); +} + +#ifdef CONFIG_WITH_COMPILER +/* Same as install_variable_buffer, except we supply a size hint. */ + +char * +install_variable_buffer_with_hint (char **bufp, unsigned int *lenp, unsigned int size_hint) +{ + struct recycled_buffer *recycled; + char *buf; + + *bufp = variable_buffer; + *lenp = variable_buffer_length; + + recycled = recycled_head; + if (recycled) + { + recycled_head = recycled->next; + variable_buffer_length = recycled->length; + variable_buffer = buf = (char *)recycled; + } + else + { + if (size_hint < 512) + variable_buffer_length = (size_hint + 1 + 63) & ~(unsigned int)63; + else if (size_hint < 4096) + variable_buffer_length = (size_hint + 1 + 1023) & ~(unsigned int)1023; + else + variable_buffer_length = (size_hint + 1 + 4095) & ~(unsigned int)4095; + variable_buffer = buf = xmalloc (variable_buffer_length); + } + buf[0] = '\0'; + return buf; +} +#endif /* CONFIG_WITH_COMPILER */ + +/* Restore a previously-saved variable_buffer setting (free the + current one). */ + +void +restore_variable_buffer (char *buf, unsigned int len) +{ +#ifndef CONFIG_WITH_VALUE_LENGTH + free (variable_buffer); +#else + if (variable_buffer) + recycle_variable_buffer (variable_buffer, variable_buffer_length); +#endif + + variable_buffer = buf; + variable_buffer_length = len; +} + + +/* Used to make sure there is at least SIZE bytes of buffer space + available starting at PTR. */ +char * +ensure_variable_buffer_space(char *ptr, unsigned int size) +{ + unsigned int offset = (unsigned int)(ptr - variable_buffer); + assert(offset <= variable_buffer_length); + if (variable_buffer_length - offset < size) + { + unsigned minlen = size + offset; + variable_buffer_length *= 2; + if (variable_buffer_length < minlen + 100) + variable_buffer_length = (minlen + 100 + 63) & ~(unsigned int)63; + variable_buffer = xrealloc (variable_buffer, variable_buffer_length); + ptr = variable_buffer + offset; + } + return ptr; +} + diff --git a/src/kmk/expreval.c b/src/kmk/expreval.c new file mode 100644 index 0000000..61f7c7b --- /dev/null +++ b/src/kmk/expreval.c @@ -0,0 +1,2387 @@ +#ifdef CONFIG_WITH_IF_CONDITIONALS +/* $Id: expreval.c 3544 2022-01-29 02:22:03Z bird $ */ +/** @file + * expreval - Expressions evaluator, C / BSD make / nmake style. + */ + +/* + * Copyright (c) 2008-2010 knut st. osmundsen + * + * This file is part of kBuild. + * + * kBuild is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * kBuild is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kBuild. If not, see + * + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "makeint.h" +#include + +#include + +#include "filedef.h" +#include "dep.h" +#include "job.h" +#include "commands.h" +#include "variable.h" +#include "rule.h" +#include "debug.h" +#include "hash.h" +#include "version_compare.h" +#include +#ifndef _MSC_VER +# include +#endif +#include + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/** The max length of a string representation of a number. */ +#define EXPR_NUM_LEN ((sizeof("-9223372036854775802") + 4) & ~3) + +/** The max operator stack depth. */ +#define EXPR_MAX_OPERATORS 72 +/** The max operand depth. */ +#define EXPR_MAX_OPERANDS 128 + +/** Check if @a a_ch is a valid separator for a alphabetical binary + * operator, omitting isspace. */ +#define EXPR_IS_OP_SEPARATOR_NO_SPACE(a_ch) \ + (ispunct((a_ch)) && (a_ch) != '@' && (a_ch) != '_') + +/** Check if @a a_ch is a valid separator for a alphabetical binary operator. */ +#define EXPR_IS_OP_SEPARATOR(a_ch) \ + (isspace((a_ch)) || EXPR_IS_OP_SEPARATOR_NO_SPACE(a_ch)) + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** The 64-bit signed integer type we're using. */ +#ifdef _MSC_VER +typedef __int64 EXPRINT64; +#else +# include +typedef int64_t EXPRINT64; +#endif + +/** Pointer to a evaluator instance. */ +typedef struct EXPR *PEXPR; + + +/** + * Operand variable type. + */ +typedef enum +{ + /** Invalid zero entry. */ + kExprVar_Invalid = 0, + /** A number. */ + kExprVar_Num, + /** A string in need of expanding (perhaps). */ + kExprVar_String, + /** A simple string that doesn't need expanding. */ + kExprVar_SimpleString, + /** A quoted string in need of expanding (perhaps). */ + kExprVar_QuotedString, + /** A simple quoted string that doesn't need expanding. */ + kExprVar_QuotedSimpleString, + /** The end of the valid variable types. */ + kExprVar_End +} EXPRVARTYPE; + +/** + * Operand variable. + */ +typedef struct +{ + /** The variable type. */ + EXPRVARTYPE enmType; + /** The variable. */ + union + { + /** Pointer to the string. */ + char *psz; + /** The variable. */ + EXPRINT64 i; + } uVal; +} EXPRVAR; +/** Pointer to a operand variable. */ +typedef EXPRVAR *PEXPRVAR; +/** Pointer to a const operand variable. */ +typedef EXPRVAR const *PCEXPRVAR; + +/** + * Operator return statuses. + */ +typedef enum +{ + kExprRet_Error = -1, + kExprRet_Ok = 0, + kExprRet_Operator, + kExprRet_Operand, + kExprRet_EndOfExpr, + kExprRet_End +} EXPRRET; + +/** + * Operator. + */ +typedef struct +{ + /** The operator. */ + char szOp[11]; + /** The length of the operator string. */ + char cchOp; + /** The pair operator. + * This is used with '(' and '?'. */ + char chPair; + /** The precedence. Higher means higher. */ + char iPrecedence; + /** The number of arguments it takes. */ + signed char cArgs; + /** Pointer to the method implementing the operator. */ + EXPRRET (*pfn)(PEXPR pThis); +} EXPROP; +/** Pointer to a const operator. */ +typedef EXPROP const *PCEXPROP; + +/** + * Expression evaluator instance. + */ +typedef struct EXPR +{ + /** The full expression. */ + const char *pszExpr; + /** The current location. */ + const char *psz; + /** The current file location, used for errors. */ + const floc *pFileLoc; + /** Pending binary operator. */ + PCEXPROP pPending; + /** Top of the operator stack. */ + int iOp; + /** Top of the operand stack. */ + int iVar; + /** The operator stack. */ + PCEXPROP apOps[EXPR_MAX_OPERATORS]; + /** The operand stack. */ + EXPRVAR aVars[EXPR_MAX_OPERANDS]; +} EXPR; + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** Operator start character map. + * This indicates which characters that are starting operators and which aren't. + * + * Bit 0: Indicates that this char is used in operators. + * Bit 1: When bit 0 is clear, this indicates whitespace. + * When bit 1 is set, this indicates whether the operator can be used + * immediately next to an operand without any clear separation. + * Bits 2 thru 7: Index into g_aExprOps of the first operator starting with + * this character. + */ +static unsigned char g_auchOpStartCharMap[256]; +/** Whether we've initialized the map. */ +static int g_fExprInitializedMap = 0; + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +static void expr_unget_op(PEXPR pThis); +static EXPRRET expr_get_binary_or_eoe_or_rparen(PEXPR pThis); + + + + +/** + * Displays an error message. + * + * The total string length must not exceed 256 bytes. + * + * @param pThis The evaluator instance. + * @param pszError The message format string. + * @param ... The message format args. + */ +static void expr_error(PEXPR pThis, const char *pszError, ...) +{ + char szTmp[256]; + va_list va; + + va_start(va, pszError); + vsprintf(szTmp, pszError, va); + va_end(va); + + OS(fatal,pThis->pFileLoc, "%s", szTmp); +} + + +/** + * Converts a number to a string. + * + * @returns pszDst. + * @param pszDst The string buffer to write into. Assumes length of EXPR_NUM_LEN. + * @param iSrc The number to convert. + */ +static char *expr_num_to_string(char *pszDst, EXPRINT64 iSrc) +{ + static const char s_szDigits[17] = "0123456789abcdef"; + char szTmp[EXPR_NUM_LEN]; + char *psz = &szTmp[EXPR_NUM_LEN - 1]; + int fNegative; + + fNegative = iSrc < 0; + if (fNegative) + { + /** @todo this isn't right for INT64_MIN. */ + iSrc = -iSrc; + } + + *psz = '\0'; + do + { +#if 0 + *--psz = s_szDigits[iSrc & 0xf]; + iSrc >>= 4; +#else + *--psz = s_szDigits[iSrc % 10]; + iSrc /= 10; +#endif + } while (iSrc); + +#if 0 + *--psz = 'x'; + *--psz = '0'; +#endif + + if (fNegative) + *--psz = '-'; + + /* copy it into the output buffer. */ + return (char *)memcpy(pszDst, psz, &szTmp[EXPR_NUM_LEN] - psz); +} + + +/** + * Attempts to convert a (simple) string into a number. + * + * @returns status code. + * @param pThis The evaluator instance. This is optional when fQuiet is true. + * @param piSrc Where to store the numeric value on success. + * @param pszSrc The string to try convert. + * @param fQuiet Whether we should be quiet or grumpy on failure. + */ +static EXPRRET expr_string_to_num(PEXPR pThis, EXPRINT64 *piDst, const char *pszSrc, int fQuiet) +{ + EXPRRET rc = kExprRet_Ok; + char const *psz = pszSrc; + EXPRINT64 i; + unsigned uBase; + int fNegative; + + + /* + * Skip blanks. + */ + while (ISBLANK(*psz)) + psz++; + + /* + * Check for '-'. + * + * At this point we will not need to deal with operators, this is + * just an indicator of negative numbers. If some operator ends up + * here it's because it came from a string expansion and thus shall + * not be interpreted. If this turns out to be an stupid restriction + * it can be fixed, but for now it stays like this. + */ + fNegative = *psz == '-'; + if (fNegative) + psz++; + + /* + * Determin base. + * + * Recognize some exsotic prefixes here in addition to the two standard ones. + */ + if (*psz != '0') + uBase = 10; + else if (psz[1] == 'x' || psz[1] == 'X') + { + uBase = 16; + psz += 2; + } + else if (psz[1] == 'b' || psz[1] == 'B') + { + uBase = 2; + psz += 2; + } + else if (psz[1] == 'd' || psz[1] == 'D') + { + uBase = 10; + psz += 2; + } + else if (psz[1] == 'o' || psz[1] == 'O') + { + uBase = 8; + psz += 2; + } + else if (isdigit(psz[1]) && psz[1] != '9' && psz[1] != '8') + { + uBase = 8; + psz++; + } + else + uBase = 10; + + /* + * Convert until we hit a non-digit. + */ + i = 0; + for (;;) + { + unsigned iDigit; + int ch = *psz; + switch (ch) + { + case '0': iDigit = 0; break; + case '1': iDigit = 1; break; + case '2': iDigit = 2; break; + case '3': iDigit = 3; break; + case '4': iDigit = 4; break; + case '5': iDigit = 5; break; + case '6': iDigit = 6; break; + case '7': iDigit = 7; break; + case '8': iDigit = 8; break; + case '9': iDigit = 9; break; + case 'a': + case 'A': iDigit = 10; break; + case 'b': + case 'B': iDigit = 11; break; + case 'c': + case 'C': iDigit = 12; break; + case 'd': + case 'D': iDigit = 13; break; + case 'e': + case 'E': iDigit = 14; break; + case 'f': + case 'F': iDigit = 15; break; + + default: + /* is the rest white space? */ + while (ISSPACE(*psz)) + psz++; + if (*psz != '\0') + { + iDigit = uBase; + break; + } + /* fall thru */ + + case '\0': + if (fNegative) + i = -i; + *piDst = i; + return rc; + } + if (iDigit >= uBase) + { + if (fNegative) + i = -i; + *piDst = i; + if (!fQuiet) + expr_error(pThis, "Invalid number \"%.80s\"", pszSrc); + return kExprRet_Error; + } + + /* add the digit and advance */ + i *= uBase; + i += iDigit; + psz++; + } + /* not reached */ +} + + +/** + * Checks if the variable is a string or not. + * + * @returns 1 if it's a string, 0 otherwise. + * @param pVar The variable. + */ +static int expr_var_is_string(PCEXPRVAR pVar) +{ + return pVar->enmType >= kExprVar_String; +} + + +/** + * Checks if the variable contains a string that was quoted + * in the expression. + * + * @returns 1 if if was a quoted string, otherwise 0. + * @param pVar The variable. + */ +static int expr_var_was_quoted(PCEXPRVAR pVar) +{ + return pVar->enmType >= kExprVar_QuotedString; +} + + +/** + * Deletes a variable. + * + * @param pVar The variable. + */ +static void expr_var_delete(PEXPRVAR pVar) +{ + if (expr_var_is_string(pVar)) + { + free(pVar->uVal.psz); + pVar->uVal.psz = NULL; + } + pVar->enmType = kExprVar_Invalid; +} + + +/** + * Initializes a new variables with a sub-string value. + * + * @param pVar The new variable. + * @param psz The start of the string value. + * @param cch The number of chars to copy. + * @param enmType The string type. + */ +static void expr_var_init_substring(PEXPRVAR pVar, const char *psz, size_t cch, EXPRVARTYPE enmType) +{ + /* convert string needing expanding into simple ones if possible. */ + if ( enmType == kExprVar_String + && !memchr(psz, '$', cch)) + enmType = kExprVar_SimpleString; + else if ( enmType == kExprVar_QuotedString + && !memchr(psz, '$', cch)) + enmType = kExprVar_QuotedSimpleString; + + pVar->enmType = enmType; + pVar->uVal.psz = xmalloc(cch + 1); + memcpy(pVar->uVal.psz, psz, cch); + pVar->uVal.psz[cch] = '\0'; +} + + +#if 0 /* unused */ +/** + * Initializes a new variables with a string value. + * + * @param pVar The new variable. + * @param psz The string value. + * @param enmType The string type. + */ +static void expr_var_init_string(PEXPRVAR pVar, const char *psz, EXPRVARTYPE enmType) +{ + expr_var_init_substring(pVar, psz, strlen(psz), enmType); +} + + +/** + * Assigns a sub-string value to a variable. + * + * @param pVar The new variable. + * @param psz The start of the string value. + * @param cch The number of chars to copy. + * @param enmType The string type. + */ +static void expr_var_assign_substring(PEXPRVAR pVar, const char *psz, size_t cch, EXPRVARTYPE enmType) +{ + expr_var_delete(pVar); + expr_var_init_substring(pVar, psz, cch, enmType); +} + + +/** + * Assignes a string value to a variable. + * + * @param pVar The variable. + * @param psz The string value. + * @param enmType The string type. + */ +static void expr_var_assign_string(PEXPRVAR pVar, const char *psz, EXPRVARTYPE enmType) +{ + expr_var_delete(pVar); + expr_var_init_string(pVar, psz, enmType); +} +#endif /* unused */ + + +/** + * Simplifies a string variable. + * + * @param pVar The variable. + */ +static void expr_var_make_simple_string(PEXPRVAR pVar) +{ + switch (pVar->enmType) + { + case kExprVar_Num: + { + char *psz = (char *)xmalloc(EXPR_NUM_LEN); + expr_num_to_string(psz, pVar->uVal.i); + pVar->uVal.psz = psz; + pVar->enmType = kExprVar_SimpleString; + break; + } + + case kExprVar_String: + case kExprVar_QuotedString: + { + char *psz; + assert(strchr(pVar->uVal.psz, '$')); + + psz = allocated_variable_expand(pVar->uVal.psz); + free(pVar->uVal.psz); + pVar->uVal.psz = psz; + + pVar->enmType = pVar->enmType == kExprVar_String + ? kExprVar_SimpleString + : kExprVar_QuotedSimpleString; + break; + } + + case kExprVar_SimpleString: + case kExprVar_QuotedSimpleString: + /* nothing to do. */ + break; + + default: + assert(0); + } +} + + +#if 0 /* unused */ +/** + * Turns a variable into a string value. + * + * @param pVar The variable. + */ +static void expr_var_make_string(PEXPRVAR pVar) +{ + switch (pVar->enmType) + { + case kExprVar_Num: + expr_var_make_simple_string(pVar); + break; + + case kExprVar_String: + case kExprVar_SimpleString: + case kExprVar_QuotedString: + case kExprVar_QuotedSimpleString: + /* nothing to do. */ + break; + + default: + assert(0); + } +} +#endif /* unused */ + + +/** + * Initializes a new variables with a integer value. + * + * @param pVar The new variable. + * @param i The integer value. + */ +static void expr_var_init_num(PEXPRVAR pVar, EXPRINT64 i) +{ + pVar->enmType = kExprVar_Num; + pVar->uVal.i = i; +} + + +/** + * Assigns a integer value to a variable. + * + * @param pVar The variable. + * @param i The integer value. + */ +static void expr_var_assign_num(PEXPRVAR pVar, EXPRINT64 i) +{ + expr_var_delete(pVar); + expr_var_init_num(pVar, i); +} + + +/** + * Turns the variable into a number. + * + * @returns status code. + * @param pThis The evaluator instance. + * @param pVar The variable. + */ +static EXPRRET expr_var_make_num(PEXPR pThis, PEXPRVAR pVar) +{ + switch (pVar->enmType) + { + case kExprVar_Num: + /* nothing to do. */ + break; + + case kExprVar_String: + expr_var_make_simple_string(pVar); + /* fall thru */ + case kExprVar_SimpleString: + { + EXPRINT64 i; + EXPRRET rc = expr_string_to_num(pThis, &i, pVar->uVal.psz, 0 /* fQuiet */); + if (rc < kExprRet_Ok) + return rc; + expr_var_assign_num(pVar, i); + break; + } + + case kExprVar_QuotedString: + case kExprVar_QuotedSimpleString: + expr_error(pThis, "Cannot convert a quoted string to a number"); + return kExprRet_Error; + + default: + assert(0); + return kExprRet_Error; + } + + return kExprRet_Ok; +} + + +/** + * Try to turn the variable into a number. + * + * @returns status code. + * @param pVar The variable. + */ +static EXPRRET expr_var_try_make_num(PEXPRVAR pVar) +{ + switch (pVar->enmType) + { + case kExprVar_Num: + /* nothing to do. */ + break; + + case kExprVar_String: + expr_var_make_simple_string(pVar); + /* fall thru */ + case kExprVar_SimpleString: + { + EXPRINT64 i; + EXPRRET rc = expr_string_to_num(NULL, &i, pVar->uVal.psz, 1 /* fQuiet */); + if (rc < kExprRet_Ok) + return rc; + expr_var_assign_num(pVar, i); + break; + } + + default: + assert(0); + case kExprVar_QuotedString: + case kExprVar_QuotedSimpleString: + /* can't do this */ + return kExprRet_Error; + } + + return kExprRet_Ok; +} + + +/** + * Initializes a new variables with a boolean value. + * + * @param pVar The new variable. + * @param f The boolean value. + */ +static void expr_var_init_bool(PEXPRVAR pVar, int f) +{ + pVar->enmType = kExprVar_Num; + pVar->uVal.i = !!f; +} + + +/** + * Assigns a boolean value to a variable. + * + * @param pVar The variable. + * @param f The boolean value. + */ +static void expr_var_assign_bool(PEXPRVAR pVar, int f) +{ + expr_var_delete(pVar); + expr_var_init_bool(pVar, f); +} + + +/** + * Turns the variable into an boolean. + * + * @returns the boolean interpretation. + * @param pVar The variable. + */ +static int expr_var_make_bool(PEXPRVAR pVar) +{ + switch (pVar->enmType) + { + case kExprVar_Num: + pVar->uVal.i = !!pVar->uVal.i; + break; + + case kExprVar_String: + expr_var_make_simple_string(pVar); + /* fall thru */ + case kExprVar_SimpleString: + { + /* + * Try convert it to a number. If that fails, use the + * GNU make boolean logic - not empty string means true. + */ + EXPRINT64 iVal; + char const *psz = pVar->uVal.psz; + while (ISBLANK(*psz)) + psz++; + if ( *psz + && expr_string_to_num(NULL, &iVal, psz, 1 /* fQuiet */) >= kExprRet_Ok) + expr_var_assign_bool(pVar, iVal != 0); + else + expr_var_assign_bool(pVar, *psz != '\0'); + break; + } + + case kExprVar_QuotedString: + expr_var_make_simple_string(pVar); + /* fall thru */ + case kExprVar_QuotedSimpleString: + /* + * Use GNU make boolean logic (not empty string means true). + * No stripping here, the string is quoted. + */ + expr_var_assign_bool(pVar, *pVar->uVal.psz != '\0'); + break; + + default: + assert(0); + break; + } + + return pVar->uVal.i; +} + + +/** + * Pops a varable off the stack and deletes it. + * @param pThis The evaluator instance. + */ +static void expr_pop_and_delete_var(PEXPR pThis) +{ + expr_var_delete(&pThis->aVars[pThis->iVar]); + pThis->iVar--; +} + + + +/** + * Tries to make the variables the same type. + * + * This will not convert numbers to strings, unless one of them + * is a quoted string. + * + * this will try convert both to numbers if neither is quoted. Both + * conversions will have to suceed for this to be commited. + * + * All strings will be simplified. + * + * @returns status code. Done complaining on failure. + * + * @param pThis The evaluator instance. + * @param pVar1 The first variable. + * @param pVar2 The second variable. + */ +static EXPRRET expr_var_unify_types(PEXPR pThis, PEXPRVAR pVar1, PEXPRVAR pVar2, const char *pszOp) +{ + /* + * Try make the variables the same type before comparing. + */ + if ( !expr_var_was_quoted(pVar1) + && !expr_var_was_quoted(pVar2)) + { + if ( expr_var_is_string(pVar1) + || expr_var_is_string(pVar2)) + { + if (!expr_var_is_string(pVar1)) + expr_var_try_make_num(pVar2); + else if (!expr_var_is_string(pVar2)) + expr_var_try_make_num(pVar1); + else + { + /* + * Both are strings, simplify them then see if both can be made into numbers. + */ + EXPRINT64 iVar1; + EXPRINT64 iVar2; + + expr_var_make_simple_string(pVar1); + expr_var_make_simple_string(pVar2); + + if ( expr_string_to_num(NULL, &iVar1, pVar1->uVal.psz, 1 /* fQuiet */) >= kExprRet_Ok + && expr_string_to_num(NULL, &iVar2, pVar2->uVal.psz, 1 /* fQuiet */) >= kExprRet_Ok) + { + expr_var_assign_num(pVar1, iVar1); + expr_var_assign_num(pVar2, iVar2); + } + } + } + } + else + { + expr_var_make_simple_string(pVar1); + expr_var_make_simple_string(pVar2); + } + + /* + * Complain if they aren't the same type now. + */ + if (expr_var_is_string(pVar1) != expr_var_is_string(pVar2)) + { + expr_error(pThis, "Unable to unify types for \"%s\"", pszOp); + return kExprRet_Error; + } + return kExprRet_Ok; +} + + +/** + * Is variable defined, unary. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_defined(PEXPR pThis) +{ + PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; + struct variable *pMakeVar; + + expr_var_make_simple_string(pVar); + pMakeVar = lookup_variable(pVar->uVal.psz, strlen(pVar->uVal.psz)); + expr_var_assign_bool(pVar, pMakeVar && *pMakeVar->value != '\0'); + + return kExprRet_Ok; +} + + +/** + * Does file(/dir/whatever) exist, unary. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_exists(PEXPR pThis) +{ + PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; + struct stat st; + + expr_var_make_simple_string(pVar); + expr_var_assign_bool(pVar, stat(pVar->uVal.psz, &st) == 0); + + return kExprRet_Ok; +} + + +/** + * Is target defined, unary. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_target(PEXPR pThis) +{ + PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; + struct file *pFile = NULL; + + /* + * Because of secondary target expansion, lookup the unexpanded + * name first. + */ +#ifdef CONFIG_WITH_2ND_TARGET_EXPANSION + if ( pVar->enmType == kExprVar_String + || pVar->enmType == kExprVar_QuotedString) + { + pFile = lookup_file(pVar->uVal.psz); + if ( pFile + && !pFile->need_2nd_target_expansion) + pFile = NULL; + } + if (!pFile) +#endif + { + expr_var_make_simple_string(pVar); + pFile = lookup_file(pVar->uVal.psz); + } + + /* + * Always inspect the head of a multiple target rule + * and look for a file with commands. + */ +#ifdef CONFIG_WITH_EXPLICIT_MULTITARGET + if (pFile && pFile->multi_head) + pFile = pFile->multi_head; +#endif + + while (pFile && !pFile->cmds) + pFile = pFile->prev; + + expr_var_assign_bool(pVar, pFile != NULL && pFile->is_target); + + return kExprRet_Ok; +} + + +/** + * Convert to boolean. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_bool(PEXPR pThis) +{ + expr_var_make_bool(&pThis->aVars[pThis->iVar]); + return kExprRet_Ok; +} + + +/** + * Convert to number, works on quoted strings too. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_num(PEXPR pThis) +{ + PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; + + /* unquote the string */ + if (pVar->enmType == kExprVar_QuotedSimpleString) + pVar->enmType = kExprVar_SimpleString; + else if (pVar->enmType == kExprVar_QuotedString) + pVar->enmType = kExprVar_String; + + return expr_var_make_num(pThis, pVar); +} + + +/** + * Performs a strlen() on the simplified/converted string argument. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_strlen(PEXPR pThis) +{ + PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; + + expr_var_make_simple_string(pVar); + expr_var_assign_num(pVar, strlen(pVar->uVal.psz)); + + return kExprRet_Ok; +} + + +/** + * Convert to string (simplified and quoted) + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_str(PEXPR pThis) +{ + PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; + + expr_var_make_simple_string(pVar); + pVar->enmType = kExprVar_QuotedSimpleString; + + return kExprRet_Ok; +} + + +/** + * Pluss (dummy / make_integer) + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_pluss(PEXPR pThis) +{ + return expr_var_make_num(pThis, &pThis->aVars[pThis->iVar]); +} + + +/** + * Minus (negate) + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_minus(PEXPR pThis) +{ + EXPRRET rc; + PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; + + rc = expr_var_make_num(pThis, pVar); + if (rc >= kExprRet_Ok) + pVar->uVal.i = -pVar->uVal.i; + + return rc; +} + + + +/** + * Bitwise NOT. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_bitwise_not(PEXPR pThis) +{ + EXPRRET rc; + PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; + + rc = expr_var_make_num(pThis, pVar); + if (rc >= kExprRet_Ok) + pVar->uVal.i = ~pVar->uVal.i; + + return rc; +} + + +/** + * Logical NOT. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_logical_not(PEXPR pThis) +{ + PEXPRVAR pVar = &pThis->aVars[pThis->iVar]; + + expr_var_make_bool(pVar); + pVar->uVal.i = !pVar->uVal.i; + + return kExprRet_Ok; +} + + +/** + * Multiplication. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_multiply(PEXPR pThis) +{ + EXPRRET rc = kExprRet_Ok; + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + + rc = expr_var_make_num(pThis, pVar1); + if (rc >= kExprRet_Ok) + { + rc = expr_var_make_num(pThis, pVar2); + if (rc >= kExprRet_Ok) + pVar1->uVal.i *= pVar2->uVal.i; + } + + expr_pop_and_delete_var(pThis); + return rc; +} + + + +/** + * Division. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_divide(PEXPR pThis) +{ + EXPRRET rc = kExprRet_Ok; + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + + rc = expr_var_make_num(pThis, pVar1); + if (rc >= kExprRet_Ok) + { + rc = expr_var_make_num(pThis, pVar2); + if (rc >= kExprRet_Ok) + pVar1->uVal.i /= pVar2->uVal.i; + } + + expr_pop_and_delete_var(pThis); + return rc; +} + + + +/** + * Modulus. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_modulus(PEXPR pThis) +{ + EXPRRET rc = kExprRet_Ok; + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + + rc = expr_var_make_num(pThis, pVar1); + if (rc >= kExprRet_Ok) + { + rc = expr_var_make_num(pThis, pVar2); + if (rc >= kExprRet_Ok) + pVar1->uVal.i %= pVar2->uVal.i; + } + + expr_pop_and_delete_var(pThis); + return rc; +} + + + +/** + * Addition (numeric). + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_add(PEXPR pThis) +{ + EXPRRET rc = kExprRet_Ok; + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + + rc = expr_var_make_num(pThis, pVar1); + if (rc >= kExprRet_Ok) + { + rc = expr_var_make_num(pThis, pVar2); + if (rc >= kExprRet_Ok) + pVar1->uVal.i += pVar2->uVal.i; + } + + expr_pop_and_delete_var(pThis); + return rc; +} + + +/** + * Subtract (numeric). + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_sub(PEXPR pThis) +{ + EXPRRET rc = kExprRet_Ok; + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + + rc = expr_var_make_num(pThis, pVar1); + if (rc >= kExprRet_Ok) + { + rc = expr_var_make_num(pThis, pVar2); + if (rc >= kExprRet_Ok) + pVar1->uVal.i -= pVar2->uVal.i; + } + + expr_pop_and_delete_var(pThis); + return rc; +} + +/** + * Bitwise left shift. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_shift_left(PEXPR pThis) +{ + EXPRRET rc = kExprRet_Ok; + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + + rc = expr_var_make_num(pThis, pVar1); + if (rc >= kExprRet_Ok) + { + rc = expr_var_make_num(pThis, pVar2); + if (rc >= kExprRet_Ok) + pVar1->uVal.i <<= pVar2->uVal.i; + } + + expr_pop_and_delete_var(pThis); + return rc; +} + + +/** + * Bitwise right shift. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_shift_right(PEXPR pThis) +{ + EXPRRET rc = kExprRet_Ok; + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + + rc = expr_var_make_num(pThis, pVar1); + if (rc >= kExprRet_Ok) + { + rc = expr_var_make_num(pThis, pVar2); + if (rc >= kExprRet_Ok) + pVar1->uVal.i >>= pVar2->uVal.i; + } + + expr_pop_and_delete_var(pThis); + return rc; +} + + +/** + * Less than or equal, version string. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_ver_less_or_equal_than(PEXPR pThis) +{ + EXPRRET rc = kExprRet_Ok; + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + + rc = expr_var_unify_types(pThis, pVar1, pVar2, "vle"); + if (rc >= kExprRet_Ok) + { + if (!expr_var_is_string(pVar1)) + expr_var_assign_bool(pVar1, pVar1->uVal.i <= pVar2->uVal.i); + else + expr_var_assign_bool(pVar1, version_compare(pVar1->uVal.psz, pVar2->uVal.psz) <= 0); + } + + expr_pop_and_delete_var(pThis); + return rc; +} + + +/** + * Less than or equal. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_less_or_equal_than(PEXPR pThis) +{ + EXPRRET rc = kExprRet_Ok; + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + + rc = expr_var_unify_types(pThis, pVar1, pVar2, "<="); + if (rc >= kExprRet_Ok) + { + if (!expr_var_is_string(pVar1)) + expr_var_assign_bool(pVar1, pVar1->uVal.i <= pVar2->uVal.i); + else + expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) <= 0); + } + + expr_pop_and_delete_var(pThis); + return rc; +} + + +/** + * Less than, version string. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_ver_less_than(PEXPR pThis) +{ + EXPRRET rc = kExprRet_Ok; + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + + rc = expr_var_unify_types(pThis, pVar1, pVar2, "vlt"); + if (rc >= kExprRet_Ok) + { + if (!expr_var_is_string(pVar1)) + expr_var_assign_bool(pVar1, pVar1->uVal.i < pVar2->uVal.i); + else + expr_var_assign_bool(pVar1, version_compare(pVar1->uVal.psz, pVar2->uVal.psz) < 0); + } + + expr_pop_and_delete_var(pThis); + return rc; +} + + +/** + * Less than. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_less_than(PEXPR pThis) +{ + EXPRRET rc = kExprRet_Ok; + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + + rc = expr_var_unify_types(pThis, pVar1, pVar2, "<"); + if (rc >= kExprRet_Ok) + { + if (!expr_var_is_string(pVar1)) + expr_var_assign_bool(pVar1, pVar1->uVal.i < pVar2->uVal.i); + else + expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) < 0); + } + + expr_pop_and_delete_var(pThis); + return rc; +} + + +/** + * Greater or equal than, version string. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_ver_greater_or_equal_than(PEXPR pThis) +{ + EXPRRET rc = kExprRet_Ok; + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + + rc = expr_var_unify_types(pThis, pVar1, pVar2, "vge"); + if (rc >= kExprRet_Ok) + { + if (!expr_var_is_string(pVar1)) + expr_var_assign_bool(pVar1, pVar1->uVal.i >= pVar2->uVal.i); + else + expr_var_assign_bool(pVar1, version_compare(pVar1->uVal.psz, pVar2->uVal.psz) >= 0); + } + + expr_pop_and_delete_var(pThis); + return rc; +} + + +/** + * Greater or equal than. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_greater_or_equal_than(PEXPR pThis) +{ + EXPRRET rc = kExprRet_Ok; + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + + rc = expr_var_unify_types(pThis, pVar1, pVar2, ">="); + if (rc >= kExprRet_Ok) + { + if (!expr_var_is_string(pVar1)) + expr_var_assign_bool(pVar1, pVar1->uVal.i >= pVar2->uVal.i); + else + expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) >= 0); + } + + expr_pop_and_delete_var(pThis); + return rc; +} + + +/** + * Greater than, version string. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_ver_greater_than(PEXPR pThis) +{ + EXPRRET rc = kExprRet_Ok; + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + + rc = expr_var_unify_types(pThis, pVar1, pVar2, "vgt"); + if (rc >= kExprRet_Ok) + { + if (!expr_var_is_string(pVar1)) + expr_var_assign_bool(pVar1, pVar1->uVal.i > pVar2->uVal.i); + else + expr_var_assign_bool(pVar1, version_compare(pVar1->uVal.psz, pVar2->uVal.psz) > 0); + } + + expr_pop_and_delete_var(pThis); + return rc; +} + + +/** + * Greater than. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_greater_than(PEXPR pThis) +{ + EXPRRET rc = kExprRet_Ok; + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + + rc = expr_var_unify_types(pThis, pVar1, pVar2, ">"); + if (rc >= kExprRet_Ok) + { + if (!expr_var_is_string(pVar1)) + expr_var_assign_bool(pVar1, pVar1->uVal.i > pVar2->uVal.i); + else + expr_var_assign_bool(pVar1, strcmp(pVar1->uVal.psz, pVar2->uVal.psz) > 0); + } + + expr_pop_and_delete_var(pThis); + return rc; +} + + +/** + * Equal, version strings. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_ver_equal(PEXPR pThis) +{ + EXPRRET rc = kExprRet_Ok; + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + int const fIsString1 = expr_var_is_string(pVar1); + + /* + * The same type? + */ + if (fIsString1 == expr_var_is_string(pVar2)) + { + if (!fIsString1) + /* numbers are simple */ + expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i); + else + { + /* try a normal string compare. */ + expr_var_make_simple_string(pVar1); + expr_var_make_simple_string(pVar2); + if (!version_compare(pVar1->uVal.psz, pVar2->uVal.psz)) + expr_var_assign_bool(pVar1, 1); + /* try convert and compare as number instead. */ + else if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok + && expr_var_try_make_num(pVar2) >= kExprRet_Ok) + expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i); + /* ok, they really aren't equal. */ + else + expr_var_assign_bool(pVar1, 0); + } + } + else + { + /* + * If the type differs, there are now two options: + * 1. Try convert the string to a valid number and compare the numbers. + * 2. Convert the non-string to a number and compare the strings. + */ + if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok + && expr_var_try_make_num(pVar2) >= kExprRet_Ok) + expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i); + else + { + expr_var_make_simple_string(pVar1); + expr_var_make_simple_string(pVar2); + expr_var_assign_bool(pVar1, version_compare(pVar1->uVal.psz, pVar2->uVal.psz) == 0); + } + } + + expr_pop_and_delete_var(pThis); + return rc; +} + + +/** + * Not equal, version string. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_ver_not_equal(PEXPR pThis) +{ + EXPRRET rc = expr_op_ver_equal(pThis); + if (rc >= kExprRet_Ok) + rc = expr_op_logical_not(pThis); + return rc; +} + + +/** + * Equal. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_equal(PEXPR pThis) +{ + EXPRRET rc = kExprRet_Ok; + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + int const fIsString1 = expr_var_is_string(pVar1); + + /* + * The same type? + */ + if (fIsString1 == expr_var_is_string(pVar2)) + { + if (!fIsString1) + /* numbers are simple */ + expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i); + else + { + /* try a normal string compare. */ + expr_var_make_simple_string(pVar1); + expr_var_make_simple_string(pVar2); + if (!strcmp(pVar1->uVal.psz, pVar2->uVal.psz)) + expr_var_assign_bool(pVar1, 1); + /* try convert and compare as number instead. */ + else if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok + && expr_var_try_make_num(pVar2) >= kExprRet_Ok) + expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i); + /* ok, they really aren't equal. */ + else + expr_var_assign_bool(pVar1, 0); + } + } + else + { + /* + * If the type differs, there are now two options: + * 1. Convert the string to a valid number and compare the numbers. + * 2. Convert an empty string to a 'false' boolean value and compare + * numerically. This one is a bit questionable, so we don't try this. + */ + if ( expr_var_try_make_num(pVar1) >= kExprRet_Ok + && expr_var_try_make_num(pVar2) >= kExprRet_Ok) + expr_var_assign_bool(pVar1, pVar1->uVal.i == pVar2->uVal.i); + else + { + expr_error(pThis, "Cannot compare strings and numbers"); + rc = kExprRet_Error; + } + } + + expr_pop_and_delete_var(pThis); + return rc; +} + + +/** + * Not equal. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_not_equal(PEXPR pThis) +{ + EXPRRET rc = expr_op_equal(pThis); + if (rc >= kExprRet_Ok) + rc = expr_op_logical_not(pThis); + return rc; +} + + +/** + * Bitwise AND. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_bitwise_and(PEXPR pThis) +{ + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + EXPRRET rc; + + rc = expr_var_make_num(pThis, pVar1); + if (rc >= kExprRet_Ok) + { + rc = expr_var_make_num(pThis, pVar2); + if (rc >= kExprRet_Ok) + pVar1->uVal.i &= pVar2->uVal.i; + } + + expr_pop_and_delete_var(pThis); + return kExprRet_Ok; +} + + +/** + * Bitwise XOR. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_bitwise_xor(PEXPR pThis) +{ + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + EXPRRET rc; + + rc = expr_var_make_num(pThis, pVar1); + if (rc >= kExprRet_Ok) + { + rc = expr_var_make_num(pThis, pVar2); + if (rc >= kExprRet_Ok) + pVar1->uVal.i ^= pVar2->uVal.i; + } + + expr_pop_and_delete_var(pThis); + return kExprRet_Ok; +} + + +/** + * Bitwise OR. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_bitwise_or(PEXPR pThis) +{ + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + EXPRRET rc; + + rc = expr_var_make_num(pThis, pVar1); + if (rc >= kExprRet_Ok) + { + rc = expr_var_make_num(pThis, pVar2); + if (rc >= kExprRet_Ok) + pVar1->uVal.i |= pVar2->uVal.i; + } + + expr_pop_and_delete_var(pThis); + return kExprRet_Ok; +} + + +/** + * Logical AND. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_logical_and(PEXPR pThis) +{ + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + + if ( expr_var_make_bool(pVar1) + && expr_var_make_bool(pVar2)) + expr_var_assign_bool(pVar1, 1); + else + expr_var_assign_bool(pVar1, 0); + + expr_pop_and_delete_var(pThis); + return kExprRet_Ok; +} + + +/** + * Logical OR. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_logical_or(PEXPR pThis) +{ + PEXPRVAR pVar1 = &pThis->aVars[pThis->iVar - 1]; + PEXPRVAR pVar2 = &pThis->aVars[pThis->iVar]; + + if ( expr_var_make_bool(pVar1) + || expr_var_make_bool(pVar2)) + expr_var_assign_bool(pVar1, 1); + else + expr_var_assign_bool(pVar1, 0); + + expr_pop_and_delete_var(pThis); + return kExprRet_Ok; +} + + +/** + * Left parenthesis. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_left_parenthesis(PEXPR pThis) +{ + /* + * There should be a right parenthesis operator lined up for us now, + * eat it. If not found there is an inbalance. + */ + EXPRRET rc = expr_get_binary_or_eoe_or_rparen(pThis); + if ( rc == kExprRet_Operator + && pThis->apOps[pThis->iOp]->szOp[0] == ')') + { + /* pop it and get another one which we can leave pending. */ + pThis->iOp--; + rc = expr_get_binary_or_eoe_or_rparen(pThis); + if (rc >= kExprRet_Ok) + expr_unget_op(pThis); + } + else + { + expr_error(pThis, "Missing ')'"); + rc = kExprRet_Error; + } + + return rc; +} + + +/** + * Right parenthesis, dummy that's never actually called. + * + * @returns Status code. + * @param pThis The instance. + */ +static EXPRRET expr_op_right_parenthesis(PEXPR pThis) +{ + assert(0); + (void)pThis; + return kExprRet_Ok; +} + + + + + +/** + * The operator table. + * + * This table is NOT ordered by precedence, but for linear search + * allowing for first match to return the correct operator. This + * means that || must come before |, or else | will match all. + */ +static const EXPROP g_aExprOps[] = +{ +#define EXPR_OP(szOp, iPrecedence, cArgs, pfn) { szOp, sizeof(szOp) - 1, '\0', iPrecedence, cArgs, pfn } + /* Name, iPrecedence, cArgs, pfn */ + EXPR_OP("defined", 90, 1, expr_op_defined), + EXPR_OP("exists", 90, 1, expr_op_exists), + EXPR_OP("target", 90, 1, expr_op_target), + EXPR_OP("bool", 90, 1, expr_op_bool), + EXPR_OP("num", 90, 1, expr_op_num), + EXPR_OP("strlen", 90, 1, expr_op_strlen), + EXPR_OP("str", 90, 1, expr_op_str), + EXPR_OP("+", 80, 1, expr_op_pluss), + EXPR_OP("-", 80, 1, expr_op_minus), + EXPR_OP("~", 80, 1, expr_op_bitwise_not), + EXPR_OP("*", 75, 2, expr_op_multiply), + EXPR_OP("/", 75, 2, expr_op_divide), + EXPR_OP("%", 75, 2, expr_op_modulus), + EXPR_OP("+", 70, 2, expr_op_add), + EXPR_OP("-", 70, 2, expr_op_sub), + EXPR_OP("<<", 65, 2, expr_op_shift_left), + EXPR_OP(">>", 65, 2, expr_op_shift_right), + EXPR_OP("<=", 60, 2, expr_op_less_or_equal_than), + EXPR_OP("<", 60, 2, expr_op_less_than), + EXPR_OP(">=", 60, 2, expr_op_greater_or_equal_than), + EXPR_OP(">", 60, 2, expr_op_greater_than), + EXPR_OP("vle", 60, 2, expr_op_ver_less_or_equal_than), + EXPR_OP("vlt", 60, 2, expr_op_ver_less_than), + EXPR_OP("vge", 60, 2, expr_op_ver_greater_or_equal_than), + EXPR_OP("vgt", 60, 2, expr_op_ver_greater_than), + EXPR_OP("==", 55, 2, expr_op_equal), + EXPR_OP("veq", 55, 2, expr_op_ver_equal), + EXPR_OP("!=", 55, 2, expr_op_not_equal), + EXPR_OP("vne", 55, 2, expr_op_ver_not_equal), + EXPR_OP("!", 80, 1, expr_op_logical_not), + EXPR_OP("^", 45, 2, expr_op_bitwise_xor), + EXPR_OP("&&", 35, 2, expr_op_logical_and), + EXPR_OP("&", 50, 2, expr_op_bitwise_and), + EXPR_OP("||", 30, 2, expr_op_logical_or), + EXPR_OP("|", 40, 2, expr_op_bitwise_or), + { "(", 1, ')', 10, 1, expr_op_left_parenthesis }, + { ")", 1, '(', 10, 0, expr_op_right_parenthesis }, + /* { "?", 1, ':', 5, 2, expr_op_question }, + { ":", 1, '?', 5, 2, expr_op_colon }, -- too weird for now. */ +#undef EXPR_OP +}; + +/** Dummy end of expression fake. */ +static const EXPROP g_ExprEndOfExpOp = +{ + "", 0, '\0', 0, 0, NULL +}; + + +/** + * Initializes the opcode character map if necessary. + */ +static void expr_map_init(void) +{ + unsigned i; + if (g_fExprInitializedMap) + return; + + /* + * Initialize it. + */ + memset(&g_auchOpStartCharMap, 0, sizeof(g_auchOpStartCharMap)); + for (i = 0; i < sizeof(g_aExprOps) / sizeof(g_aExprOps[0]); i++) + { + unsigned int ch = (unsigned int)g_aExprOps[i].szOp[0]; + if (!g_auchOpStartCharMap[ch]) + { + g_auchOpStartCharMap[ch] = (i << 2) | 1; + if (!isalpha(ch)) + g_auchOpStartCharMap[ch] |= 2; /* Need no clear separation from operands. */ + } + } + + /* whitespace (assumes C-like locale because I'm lazy): */ +#define SET_WHITESPACE(a_ch) do { \ + assert(g_auchOpStartCharMap[(unsigned char)(a_ch)] == 0); \ + g_auchOpStartCharMap[(unsigned char)(a_ch)] |= 2; \ + } while (0) + SET_WHITESPACE(' '); + SET_WHITESPACE('\t'); + SET_WHITESPACE('\n'); + SET_WHITESPACE('\r'); + SET_WHITESPACE('\v'); + SET_WHITESPACE('\f'); + + g_fExprInitializedMap = 1; +} + + +/** + * Looks up a character in the map. + * + * @returns the value for that char, see g_auchOpStartCharMap for details. + * @param ch The character. + */ +static unsigned char expr_map_get(char ch) +{ + return g_auchOpStartCharMap[(unsigned char)ch]; +} + + +/** + * Searches the operator table given a potential operator start char. + * + * @returns Pointer to the matching operator. NULL if not found. + * @param psz Pointer to what can be an operator. + * @param uchVal The expr_map_get value. + * @param fUnary Whether it must be an unary operator or not. + */ +static PCEXPROP expr_lookup_op(char const *psz, unsigned char uchVal, int fUnary) +{ + char ch = *psz; + unsigned i; + assert((uchVal & 2) == (isalpha(ch) ? 0 : 2)); + + for (i = uchVal >> 2; i < sizeof(g_aExprOps) / sizeof(g_aExprOps[0]); i++) + { + /* compare the string... */ + if (g_aExprOps[i].szOp[0] != ch) + continue; + switch (g_aExprOps[i].cchOp) + { + case 1: + break; + case 2: + if (g_aExprOps[i].szOp[1] != psz[1]) + continue; + break; + default: + if (strncmp(&g_aExprOps[i].szOp[1], psz + 1, g_aExprOps[i].cchOp - 1)) + continue; + break; + } + + /* ... and the operator type. */ + if (fUnary == (g_aExprOps[i].cArgs == 1)) + { + /* Check if we've got the needed operand separation: */ + if ( (uchVal & 2) + || EXPR_IS_OP_SEPARATOR(psz[g_aExprOps[i].cchOp])) + { + /* got a match! */ + return &g_aExprOps[i]; + } + } + } + + return NULL; +} + + +/** + * Ungets a binary operator. + * + * The operator is poped from the stack and put in the pending position. + * + * @param pThis The evaluator instance. + */ +static void expr_unget_op(PEXPR pThis) +{ + assert(pThis->pPending == NULL); + assert(pThis->iOp >= 0); + + pThis->pPending = pThis->apOps[pThis->iOp]; + pThis->apOps[pThis->iOp] = NULL; + pThis->iOp--; +} + + + +/** + * Get the next token, it should be a binary operator, or the end of + * the expression, or a right parenthesis. + * + * The operator is pushed onto the stack and the status code indicates + * which of the two we found. + * + * @returns status code. Will grumble on failure. + * @retval kExprRet_EndOfExpr if we encountered the end of the expression. + * @retval kExprRet_Operator if we encountered a binary operator or right + * parenthesis. It's on the operator stack. + * + * @param pThis The evaluator instance. + */ +static EXPRRET expr_get_binary_or_eoe_or_rparen(PEXPR pThis) +{ + /* + * See if there is anything pending first. + */ + PCEXPROP pOp = pThis->pPending; + if (pOp) + pThis->pPending = NULL; + else + { + /* + * Eat more of the expression. + */ + char const *psz = pThis->psz; + + /* spaces */ + unsigned char uchVal; + char ch; + while (((uchVal = expr_map_get((ch = *psz))) & 3) == 2) + psz++; + + /* see what we've got. */ + if (ch) + { + if (uchVal & 1) + pOp = expr_lookup_op(psz, uchVal, 0 /* fUnary */); + if (!pOp) + { + expr_error(pThis, "Expected binary operator, found \"%.42s\"...", psz); + return kExprRet_Error; + } + psz += pOp->cchOp; + } + else + pOp = &g_ExprEndOfExpOp; + pThis->psz = psz; + } + + /* + * Push it. + */ + if (pThis->iOp >= EXPR_MAX_OPERATORS - 1) + { + expr_error(pThis, "Operator stack overflow"); + return kExprRet_Error; + } + pThis->apOps[++pThis->iOp] = pOp; + + return pOp->iPrecedence + ? kExprRet_Operator + : kExprRet_EndOfExpr; +} + + + +/** + * Get the next token, it should be an unary operator or an operand. + * + * This will fail if encountering the end of the expression since + * it is implied that there should be something more. + * + * The token is pushed onto the respective stack and the status code + * indicates which it is. + * + * @returns status code. On failure we'll be done bitching already. + * @retval kExprRet_Operator if we encountered an unary operator. + * It's on the operator stack. + * @retval kExprRet_Operand if we encountered an operand operator. + * It's on the operand stack. + * + * @param This The evaluator instance. + */ +static EXPRRET expr_get_unary_or_operand(PEXPR pThis) +{ + EXPRRET rc; + unsigned char uchVal; + PCEXPROP pOp; + char const *psz = pThis->psz; + char ch; + + /* + * Eat white space and make sure there is something after it. + */ + while (((uchVal = expr_map_get((ch = *psz))) & 3) == 2) + psz++; + if (ch == '\0') + { + expr_error(pThis, "Unexpected end of expression"); + return kExprRet_Error; + } + + /* + * Is it an operator? + */ + pOp = NULL; + if (uchVal & 1) + pOp = expr_lookup_op(psz, uchVal, 1 /* fUnary */); + if (pOp) + { + /* + * Push the operator onto the stack. + */ + if (pThis->iVar < EXPR_MAX_OPERANDS - 1) + { + pThis->apOps[++pThis->iOp] = pOp; + rc = kExprRet_Operator; + } + else + { + expr_error(pThis, "Operator stack overflow"); + rc = kExprRet_Error; + } + psz += pOp->cchOp; + } + else if (pThis->iVar < EXPR_MAX_OPERANDS - 1) + { + /* + * It's an operand. Figure out where it ends and + * push it onto the stack. + */ + const char *pszStart; + + rc = kExprRet_Ok; + if (ch == '"') + { + pszStart = ++psz; + while ((ch = *psz) != '\0' && ch != '"') + psz++; + expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_QuotedString); + if (ch != '\0') + psz++; + } + else if (ch == '\'') + { + pszStart = ++psz; + while ((ch = *psz) != '\0' && ch != '\'') + psz++; + expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_QuotedSimpleString); + if (ch != '\0') + psz++; + } + else + { + char achPars[20]; + int iPar = -1; + char chEndPar = '\0'; + + pszStart = psz; + while ((ch = *psz) != '\0') + { + char ch2; + + /* $(adsf) or ${asdf} needs special handling. */ + if ( ch == '$' + && ( (ch2 = psz[1]) == '(' + || ch2 == '{')) + { + psz++; + if (iPar > (int)(sizeof(achPars) / sizeof(achPars[0]))) + { + expr_error(pThis, "Too deep nesting of variable expansions"); + rc = kExprRet_Error; + break; + } + achPars[++iPar] = chEndPar = ch2 == '(' ? ')' : '}'; + } + else if (ch == chEndPar) + { + iPar--; + chEndPar = iPar >= 0 ? achPars[iPar] : '\0'; + } + else if (!chEndPar) + { + uchVal = expr_map_get(ch); + if (uchVal == 0) + { /*likely*/ } + else if ((uchVal & 3) == 2 /*isspace*/) + break; + else if ( (uchVal & 1) + && psz != pszStart /* not at the start */ + && ( (uchVal & 2) /* operator without separator needs */ + || EXPR_IS_OP_SEPARATOR_NO_SPACE(psz[-1]))) + { + pOp = expr_lookup_op(psz, uchVal, 0 /* fUnary */); + if (pOp) + break; + } + } + + /* next */ + psz++; + } + + if (rc == kExprRet_Ok) + expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_String); + } + } + else + { + expr_error(pThis, "Operand stack overflow"); + rc = kExprRet_Error; + } + pThis->psz = psz; + + return rc; +} + + +/** + * Evaluates the current expression. + * + * @returns status code. + * + * @param pThis The instance. + */ +static EXPRRET expr_eval(PEXPR pThis) +{ + EXPRRET rc; + PCEXPROP pOp; + + /* + * The main loop. + */ + for (;;) + { + /* + * Eat unary operators until we hit an operand. + */ + do rc = expr_get_unary_or_operand(pThis); + while (rc == kExprRet_Operator); + if (rc < kExprRet_Ok) + break; + + /* + * Look for a binary operator, right parenthesis or end of expression. + */ + rc = expr_get_binary_or_eoe_or_rparen(pThis); + if (rc < kExprRet_Ok) + break; + expr_unget_op(pThis); + + /* + * Pop operators and apply them. + * + * Parenthesis will be handed via precedence, where the left parenthesis + * will go pop the right one and make another operator pending. + */ + while ( pThis->iOp >= 0 + && pThis->apOps[pThis->iOp]->iPrecedence >= pThis->pPending->iPrecedence) + { + pOp = pThis->apOps[pThis->iOp--]; + assert(pThis->iVar + 1 >= pOp->cArgs); + rc = pOp->pfn(pThis); + if (rc < kExprRet_Ok) + break; + } + if (rc < kExprRet_Ok) + break; + + /* + * Get the next binary operator or end of expression. + * There should be no right parenthesis here. + */ + rc = expr_get_binary_or_eoe_or_rparen(pThis); + if (rc < kExprRet_Ok) + break; + pOp = pThis->apOps[pThis->iOp]; + if (!pOp->iPrecedence) + break; /* end of expression */ + if (!pOp->cArgs) + { + expr_error(pThis, "Unexpected \"%s\"", pOp->szOp); + rc = kExprRet_Error; + break; + } + } + + return rc; +} + + +/** + * Destroys the given instance. + * + * @param pThis The instance to destroy. + */ +static void expr_destroy(PEXPR pThis) +{ + while (pThis->iVar >= 0) + { + expr_var_delete(pThis->aVars); + pThis->iVar--; + } + free(pThis); +} + + +/** + * Instantiates an expression evaluator. + * + * @returns The instance. + * + * @param pszExpr What to parse. + * This must stick around until expr_destroy. + */ +static PEXPR expr_create(char const *pszExpr) +{ + PEXPR pThis = (PEXPR)xmalloc(sizeof(*pThis)); + pThis->pszExpr = pszExpr; + pThis->psz = pszExpr; + pThis->pFileLoc = NULL; + pThis->pPending = NULL; + pThis->iVar = -1; + pThis->iOp = -1; + + expr_map_init(); + return pThis; +} + + +/** + * Evaluates the given if expression. + * + * @returns -1, 0 or 1. (GNU make conditional check convention, see read.c.) + * @retval -1 if the expression is invalid. + * @retval 0 if the expression is true + * @retval 1 if the expression is false. + * + * @param line The expression. + * @param flocp The file location, used for errors. + */ +int expr_eval_if_conditionals(const char *line, const floc *flocp) +{ + /* + * Instantiate the expression evaluator and let + * it have a go at it. + */ + int rc = -1; + PEXPR pExpr = expr_create(line); + pExpr->pFileLoc = flocp; + if (expr_eval(pExpr) >= kExprRet_Ok) + { + /* + * Convert the result (on top of the stack) to boolean and + * set our return value accordingly. + */ + if (expr_var_make_bool(&pExpr->aVars[0])) + rc = 0; + else + rc = 1; + } + expr_destroy(pExpr); + + return rc; +} + + +/** + * Evaluates the given expression and returns the result as a string. + * + * @returns variable buffer position. + * + * @param o The current variable buffer position. + * @param expr The expression. + */ +char *expr_eval_to_string(char *o, const char *expr) +{ + /* + * Instantiate the expression evaluator and let + * it have a go at it. + */ + PEXPR pExpr = expr_create(expr); + if (expr_eval(pExpr) >= kExprRet_Ok) + { + /* + * Convert the result (on top of the stack) to a string + * and copy it out the variable buffer. + */ + PEXPRVAR pVar = &pExpr->aVars[0]; + expr_var_make_simple_string(pVar); + o = variable_buffer_output(o, pVar->uVal.psz, strlen(pVar->uVal.psz)); + } + else + o = variable_buffer_output(o, "", sizeof("") - 1); + expr_destroy(pExpr); + + return o; +} + + +#endif /* CONFIG_WITH_IF_CONDITIONALS */ + diff --git a/src/kmk/file.c b/src/kmk/file.c new file mode 100644 index 0000000..888d639 --- /dev/null +++ b/src/kmk/file.c @@ -0,0 +1,1458 @@ +/* Target file management for GNU Make. +Copyright (C) 1988-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#include "makeint.h" + +#include + +#include "filedef.h" +#include "dep.h" +#include "job.h" +#include "commands.h" +#include "variable.h" +#include "debug.h" +#include "hash.h" +#ifdef CONFIG_WITH_STRCACHE2 +# include +#endif + + +/* Remember whether snap_deps has been invoked: we need this to be sure we + don't add new rules (via $(eval ...)) afterwards. In the future it would + be nice to support this, but it means we'd need to re-run snap_deps() or + at least its functionality... it might mean changing snap_deps() to be run + per-file, so we can invoke it after the eval... or remembering which files + in the hash have been snapped (a new boolean flag?) and having snap_deps() + only work on files which have not yet been snapped. */ +int snapped_deps = 0; + +/* Hash table of files the makefile knows how to make. */ + +#ifndef CONFIG_WITH_STRCACHE2 +static unsigned long +file_hash_1 (const void *key) +{ + return_ISTRING_HASH_1 (((struct file const *) key)->hname); +} + +static unsigned long +file_hash_2 (const void *key) +{ + return_ISTRING_HASH_2 (((struct file const *) key)->hname); +} +#endif /* !CONFIG_WITH_STRCACHE2 */ + +static int +file_hash_cmp (const void *x, const void *y) +{ +#ifndef CONFIG_WITH_STRCACHE2 + return_ISTRING_COMPARE (((struct file const *) x)->hname, + ((struct file const *) y)->hname); +#else /* CONFIG_WITH_STRCACHE2 */ + return ((struct file const *) x)->hname + == ((struct file const *) y)->hname ? 0 : -1; +#endif /* CONFIG_WITH_STRCACHE2 */ +} + +static struct hash_table files; + +/* Whether or not .SECONDARY with no prerequisites was given. */ +static int all_secondary = 0; + +/* Access the hash table of all file records. + lookup_file given a name, return the struct file * for that name, + or nil if there is none. +*/ + +#ifndef CONFIG_WITH_STRCACHE2 +struct file * +lookup_file (const char *name) +#else /* CONFIG_WITH_STRCACHE2 */ +MY_INLINE struct file * +lookup_file_common (const char *name, int cached) +#endif /* CONFIG_WITH_STRCACHE2 */ +{ + struct file *f; + struct file file_key; +#ifdef VMS + int want_vmsify; +#ifndef WANT_CASE_SENSITIVE_TARGETS + char *lname; +#endif +#endif + + assert (*name != '\0'); + + /* This is also done in parse_file_seq, so this is redundant + for names read from makefiles. It is here for names passed + on the command line. */ +#ifdef VMS + want_vmsify = (strpbrk (name, "]>:^") != NULL); +# ifndef WANT_CASE_SENSITIVE_TARGETS + if (*name != '.') + { + const char *n; + char *ln; + lname = xstrdup (name); + for (n = name, ln = lname; *n != '\0'; ++n, ++ln) + *ln = isupper ((unsigned char)*n) ? tolower ((unsigned char)*n) : *n; + *ln = '\0'; + name = lname; + } +# endif + + while (name[0] == '[' && name[1] == ']' && name[2] != '\0') + name += 2; + while (name[0] == '<' && name[1] == '>' && name[2] != '\0') + name += 2; +#endif + while (name[0] == '.' +#ifdef HAVE_DOS_PATHS + && (name[1] == '/' || name[1] == '\\') +#else + && name[1] == '/' +#endif + && name[2] != '\0') + { + name += 2; + while (*name == '/' +#ifdef HAVE_DOS_PATHS + || *name == '\\' +#endif + ) + /* Skip following slashes: ".//foo" is "foo", not "/foo". */ + ++name; + } + + if (*name == '\0') + { + /* It was all slashes after a dot. */ +#if defined(_AMIGA) + name = ""; +#else + name = "./"; +#endif +#if defined(VMS) + /* TODO - This section is probably not needed. */ + if (want_vmsify) + name = "[]"; +#endif + } +#ifndef CONFIG_WITH_STRCACHE2 + file_key.hname = name; + f = hash_find_item (&files, &file_key); +#else /* CONFIG_WITH_STRCACHE2 */ + if (!cached) + { + file_key.hname = strcache2_lookup_file (&file_strcache, name, strlen (name)); + if (file_key.hname) + f = hash_find_item_strcached (&files, &file_key); + else + f = NULL; + } + else + { + file_key.hname = name; + f = hash_find_item_strcached (&files, &file_key); + } + +#endif /* CONFIG_WITH_STRCACHE2 */ +#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) + if (*name != '.') + free (lname); +#endif + + return f; +} + +#ifdef CONFIG_WITH_STRCACHE2 +/* Given a name, return the struct file * for that name, + or nil if there is none. */ + +struct file * +lookup_file (const char *name) +{ + return lookup_file_common (name, 0 /* cached */); +} + +/* Given a name in the strcache, return the struct file * for that name, + or nil if there is none. */ +struct file * +lookup_file_cached (const char *name) +{ + assert (strcache_iscached (name)); + return lookup_file_common (name, 1 /* cached */); +} +#endif /* CONFIG_WITH_STRCACHE2 */ + + +/* Look up a file record for file NAME and return it. + Create a new record if one doesn't exist. NAME will be stored in the + new record so it should be constant or in the strcache etc. + */ + +struct file * +enter_file (const char *name) +{ + struct file *f; + struct file *new; + struct file **file_slot; + struct file file_key; + + assert (*name != '\0'); + assert (! verify_flag || strcache_iscached (name)); + +#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) + if (*name != '.') + { + const char *n; + char *lname, *ln; + lname = xstrdup (name); + for (n = name, ln = lname; *n != '\0'; ++n, ++ln) + if (isupper ((unsigned char)*n)) + *ln = tolower ((unsigned char)*n); + else + *ln = *n; + + *ln = '\0'; + name = strcache_add (lname); + free (lname); + } +#endif + + file_key.hname = name; +#ifndef CONFIG_WITH_STRCACHE2 + file_slot = (struct file **) hash_find_slot (&files, &file_key); +#else /* CONFIG_WITH_STRCACHE2 */ + file_slot = (struct file **) hash_find_slot_strcached (&files, &file_key); +#endif /* CONFIG_WITH_STRCACHE2 */ + f = *file_slot; + if (! HASH_VACANT (f) && !f->double_colon) + { + f->builtin = 0; + return f; + } + +#ifndef CONFIG_WITH_ALLOC_CACHES + new = xcalloc (sizeof (struct file)); +#else + new = alloccache_calloc (&file_cache); +#endif + new->name = new->hname = name; + new->update_status = us_none; + + if (HASH_VACANT (f)) + { + new->last = new; + hash_insert_at (&files, new, file_slot); + } + else + { + /* There is already a double-colon entry for this file. */ + new->double_colon = f; + f->last->prev = new; + f->last = new; + } + +#ifdef CONFIG_WITH_2ND_TARGET_EXPANSION + /* Check if the name needs 2nd expansion or not. */ + if (second_target_expansion && strchr (name, '$') != NULL) + new->need_2nd_target_expansion = 1; +#endif + + return new; +} + +/* Rehash FILE to NAME. This is not as simple as resetting + the 'hname' member, since it must be put in a new hash bucket, + and possibly merged with an existing file called NAME. */ + +void +rehash_file (struct file *from_file, const char *to_hname) +{ + struct file file_key; + struct file **file_slot; + struct file *to_file; + struct file *deleted_file; + struct file *f; + +#ifdef CONFIG_WITH_STRCACHE2 + assert (strcache_iscached (to_hname)); + assert (strcache_iscached (from_file->hname)); +#endif + + /* If it's already that name, we're done. */ + from_file->builtin = 0; + file_key.hname = to_hname; + if (! file_hash_cmp (from_file, &file_key)) + return; + + /* Find the end of the renamed list for the "from" file. */ + file_key.hname = from_file->hname; + while (from_file->renamed != 0) + from_file = from_file->renamed; + if (file_hash_cmp (from_file, &file_key)) + /* hname changed unexpectedly!! */ + abort (); + + /* Remove the "from" file from the hash. */ +#ifndef CONFIG_WITH_STRCACHE2 + deleted_file = hash_delete (&files, from_file); +#else + deleted_file = hash_delete_strcached (&files, from_file); +#endif + if (deleted_file != from_file) + /* from_file isn't the one stored in files */ + abort (); + + /* Find where the newly renamed file will go in the hash. */ + file_key.hname = to_hname; +#ifndef CONFIG_WITH_STRCACHE2 + file_slot = (struct file **) hash_find_slot (&files, &file_key); +#else /* CONFIG_WITH_STRCACHE2 */ + file_slot = (struct file **) hash_find_slot_strcached (&files, &file_key); +#endif /* CONFIG_WITH_STRCACHE2 */ + to_file = *file_slot; + + /* Change the hash name for this file. */ + from_file->hname = to_hname; + for (f = from_file->double_colon; f != 0; f = f->prev) + f->hname = to_hname; + + /* If the new name doesn't exist yet just set it to the renamed file. */ + if (HASH_VACANT (to_file)) + { + hash_insert_at (&files, from_file, file_slot); + return; + } + + /* TO_FILE already exists under TO_HNAME. + We must retain TO_FILE and merge FROM_FILE into it. */ + + if (from_file->cmds != 0) + { + if (to_file->cmds == 0) + to_file->cmds = from_file->cmds; + else if (from_file->cmds != to_file->cmds) + { + size_t l = strlen (from_file->name); + /* We have two sets of commands. We will go with the + one given in the rule explicitly mentioning this name, + but give a message to let the user know what's going on. */ + if (to_file->cmds->fileinfo.filenm != 0) + error (&from_file->cmds->fileinfo, + l + strlen (to_file->cmds->fileinfo.filenm) + INTSTR_LENGTH, + _("Recipe was specified for file '%s' at %s:%lu,"), + from_file->name, to_file->cmds->fileinfo.filenm, + to_file->cmds->fileinfo.lineno); + else + error (&from_file->cmds->fileinfo, l, + _("Recipe for file '%s' was found by implicit rule search,"), + from_file->name); + l += strlen (to_hname); + error (&from_file->cmds->fileinfo, l, + _("but '%s' is now considered the same file as '%s'."), + from_file->name, to_hname); + error (&from_file->cmds->fileinfo, l, + _("Recipe for '%s' will be ignored in favor of the one for '%s'."), + to_hname, from_file->name); + } + } + +#ifdef CONFIG_WITH_EXPLICIT_MULTITARGET + /* Merge multi target attributes and considerations. */ + if (from_file->multi_head) + { + if (to_file->multi_head) + OSS (fatal, NILF, _("can't rename/merge multi target '%s' with multi target '%s'"), + from_file->name, to_hname); + + to_file->multi_maybe = from_file->multi_maybe; + to_file->multi_next = from_file->multi_next; + to_file->multi_head = f = from_file->multi_head; + if (f == from_file) + { + for (; f != 0; f = f->multi_next) + f->multi_head = to_file; + to_file->multi_head = to_file; + } + else + { + while (f->multi_next != from_file) + f = f->multi_next; + assert(f->multi_next == from_file); + f->multi_next = to_file; + } +# ifdef NDEBUG + from_file->multi_head = to_file->multi_head; + from_file->multi_next = NULL; +# else + from_file->multi_head = (struct file *)0x2; /* poison */ + from_file->multi_next = (struct file *)0x8; +# endif + } +#endif + + /* Merge the dependencies of the two files. */ + + if (to_file->deps == 0) + to_file->deps = from_file->deps; + else + { + struct dep *deps = to_file->deps; + while (deps->next != 0) + deps = deps->next; + deps->next = from_file->deps; + } + + merge_variable_set_lists (&to_file->variables, from_file->variables); + + if (to_file->double_colon && from_file->is_target && !from_file->double_colon) + OSS (fatal, NILF, _("can't rename single-colon '%s' to double-colon '%s'"), + from_file->name, to_hname); + if (!to_file->double_colon && from_file->double_colon) + { + if (to_file->is_target) + OSS (fatal, NILF, + _("can't rename double-colon '%s' to single-colon '%s'"), + from_file->name, to_hname); + else + to_file->double_colon = from_file->double_colon; + } + + if (from_file->last_mtime > to_file->last_mtime) + /* %%% Kludge so -W wins on a file that gets vpathized. */ + to_file->last_mtime = from_file->last_mtime; + + to_file->mtime_before_update = from_file->mtime_before_update; + +#define MERGE(field) to_file->field |= from_file->field + MERGE (precious); + MERGE (tried_implicit); + MERGE (updating); + MERGE (updated); + MERGE (is_target); + MERGE (cmd_target); + MERGE (phony); + MERGE (loaded); + MERGE (ignore_vpath); +#undef MERGE + + to_file->builtin = 0; + from_file->renamed = to_file; +} + +/* Rename FILE to NAME. This is not as simple as resetting + the 'name' member, since it must be put in a new hash bucket, + and possibly merged with an existing file called NAME. */ + +void +rename_file (struct file *from_file, const char *to_hname) +{ + rehash_file (from_file, to_hname); + while (from_file) + { + from_file->name = from_file->hname; + from_file = from_file->prev; + } +} + +#ifdef CONFIG_WITH_2ND_TARGET_EXPANSION +/* Performs secondary target name expansion and then renames + the file using rename_file. */ +static void +do_2nd_target_expansion (struct file *f) +{ + unsigned int len; + char *tmp_name = allocated_variable_expand_2 ( + f->name, strcache2_get_len (&file_strcache, f->name), &len); + const char *name = strcache_add_len (tmp_name, len); + free (tmp_name); + rename_file (f, name); +} +#endif /* CONFIG_WITH_2ND_TARGET_EXPANSION */ + +/* Remove all nonprecious intermediate files. + If SIG is nonzero, this was caused by a fatal signal, + meaning that a different message will be printed, and + the message will go to stderr rather than stdout. */ + +void +remove_intermediates (int sig) +{ + struct file **file_slot; + struct file **file_end; + int doneany = 0; + + /* If there's no way we will ever remove anything anyway, punt early. */ + if (question_flag || touch_flag || all_secondary) + return; + + if (sig && just_print_flag) + return; + + file_slot = (struct file **) files.ht_vec; + file_end = file_slot + files.ht_size; + for ( ; file_slot < file_end; file_slot++) + if (! HASH_VACANT (*file_slot)) + { + struct file *f = *file_slot; + /* Is this file eligible for automatic deletion? + Yes, IFF: it's marked intermediate, it's not secondary, it wasn't + given on the command line, and it's either a -include makefile or + it's not precious. */ + if (f->intermediate && (f->dontcare || !f->precious) + && !f->secondary && !f->cmd_target) + { + int status; + if (f->update_status == us_none) + /* If nothing would have created this file yet, + don't print an "rm" command for it. */ + continue; + if (just_print_flag) + status = 0; + else + { + status = unlink (f->name); + if (status < 0 && errno == ENOENT) + continue; + } + if (!f->dontcare) + { + if (sig) + OS (error, NILF, + _("*** Deleting intermediate file '%s'"), f->name); + else + { + if (! doneany) + DB (DB_BASIC, (_("Removing intermediate files...\n"))); + if (!silent_flag) + { + if (! doneany) + { + fputs ("rm ", stdout); + doneany = 1; + } + else + putchar (' '); + fputs (f->name, stdout); + fflush (stdout); + } + } + if (status < 0) + perror_with_name ("unlink: ", f->name); + } + } + } + + if (doneany && !sig) + { + putchar ('\n'); + fflush (stdout); + } +} + +/* Given a string containing prerequisites (fully expanded), break it up into + a struct dep list. Enter each of these prereqs into the file database. + */ +struct dep * +split_prereqs (char *p) +{ + struct dep *new = PARSE_FILE_SEQ (&p, struct dep, MAP_PIPE, NULL, + PARSEFS_NONE); + + if (*p) + { + /* Files that follow '|' are "order-only" prerequisites that satisfy the + dependency by existing: their modification times are irrelevant. */ + struct dep *ood; + + ++p; + ood = PARSE_SIMPLE_SEQ (&p, struct dep); + + if (! new) + new = ood; + else + { + struct dep *dp; + for (dp = new; dp->next != NULL; dp = dp->next) + ; + dp->next = ood; + } + + for (; ood != NULL; ood = ood->next) + ood->ignore_mtime = 1; + } + + return new; +} + +/* Given a list of prerequisites, enter them into the file database. + If STEM is set then first expand patterns using STEM. */ +struct dep * +enter_prereqs (struct dep *deps, const char *stem) +{ + struct dep *d1; + + if (deps == 0) + return 0; + + /* If we have a stem, expand the %'s. We use patsubst_expand to translate + the prerequisites' patterns into plain prerequisite names. */ + if (stem) + { + const char *pattern = "%"; + char *buffer = variable_expand (""); + struct dep *dp = deps, *dl = 0; + + while (dp != 0) + { + char *percent; + int nl = strlen (dp->name) + 1; + char *nm = alloca (nl); + memcpy (nm, dp->name, nl); + percent = find_percent (nm); + if (percent) + { + char *o; + + /* We have to handle empty stems specially, because that + would be equivalent to $(patsubst %,dp->name,) which + will always be empty. */ + if (stem[0] == '\0') + { + memmove (percent, percent+1, strlen (percent)); + o = variable_buffer_output (buffer, nm, strlen (nm) + 1); + } + else + o = patsubst_expand_pat (buffer, stem, pattern, nm, + pattern+1, percent+1); + + /* If the name expanded to the empty string, ignore it. */ + if (buffer[0] == '\0') + { + struct dep *df = dp; + if (dp == deps) + dp = deps = deps->next; + else + dp = dl->next = dp->next; + free_dep (df); + continue; + } + + /* Save the name. */ + dp->name = strcache_add_len (buffer, o - buffer); + } + dp->stem = stem; + dp->staticpattern = 1; + dl = dp; + dp = dp->next; + } + } + + /* Enter them as files, unless they need a 2nd expansion. */ + for (d1 = deps; d1 != 0; d1 = d1->next) + { + if (d1->need_2nd_expansion) + continue; + + d1->file = lookup_file (d1->name); + if (d1->file == 0) + d1->file = enter_file (d1->name); + d1->staticpattern = 0; + d1->name = 0; + } + + return deps; +} + +/* Set the intermediate flag. */ + +static void +set_intermediate (const void *item) +{ + struct file *f = (struct file *) item; + f->intermediate = 1; +} + +/* Expand and parse each dependency line. */ +static void +expand_deps (struct file *f) +{ + struct dep *d; + struct dep **dp; + const char *file_stem = f->stem; + int initialized = 0; + + f->updating = 0; + + /* Walk through the dependencies. For any dependency that needs 2nd + expansion, expand it then insert the result into the list. */ + dp = &f->deps; + d = f->deps; + while (d != 0) + { + char *p; + struct dep *new, *next; + char *name = (char *)d->name; + + if (! d->name || ! d->need_2nd_expansion) + { + /* This one is all set already. */ + dp = &d->next; + d = d->next; + continue; + } + +#ifdef CONFIG_WITH_INCLUDEDEP + /* Dependencies loaded by includedep are ready for use and we skip + the expensive parsing and globbing for them. */ + + if (d->includedep) + { + d->need_2nd_expansion = 0; + d->file = lookup_file (name); + if (d->file == 0) + d->file = enter_file (name); + d->name = 0; + free(name); + + dp = &d->next; + d = d->next; + continue; + } +#endif /* CONFIG_WITH_INCLUDEDEP */ + + /* If it's from a static pattern rule, convert the patterns into + "$*" so they'll expand properly. */ + if (d->staticpattern) + { + char *o = variable_expand (""); + o = subst_expand (o, name, "%", "$*", 1, 2, 0); + *o = '\0'; +#ifndef CONFIG_WITH_STRCACHE2 + free (name); + d->name = name = xstrdup (variable_buffer); /* bird not d->name, can be reallocated */ +#else + d->name = strcache2_add (&file_strcache, variable_buffer, o - variable_buffer); +#endif + d->staticpattern = 0; + } + + /* We're going to do second expansion so initialize file variables for + the file. Since the stem for static pattern rules comes from + individual dep lines, we will temporarily set f->stem to d->stem. */ + if (!initialized) + { + initialize_file_variables (f, 0); + initialized = 1; + } + + if (d->stem != 0) + f->stem = d->stem; + +#if defined(CONFIG_WITH_COMMANDS_FUNC) || defined (CONFIG_WITH_DOT_MUST_MAKE) + set_file_variables (f, 0 /* real call, f->deps == 0 so we're ok. */); +#else + set_file_variables (f); +#endif + + p = variable_expand_for_file (d->name, f); + + if (d->stem != 0) + f->stem = file_stem; + + /* At this point we don't need the name anymore: free it. */ + free (name); + + /* Parse the prerequisites and enter them into the file database. */ + new = enter_prereqs (split_prereqs (p), d->stem); + + /* If there were no prereqs here (blank!) then throw this one out. */ + if (new == 0) + { + *dp = d->next; + free_dep (d); + d = *dp; + continue; + } + + /* Add newly parsed prerequisites. */ + next = d->next; +#ifdef KMK /* bird: memory leak */ + assert(new != d); + free_dep (d); +#endif + *dp = new; + for (dp = &new->next, d = new->next; d != 0; dp = &d->next, d = d->next) + ; + *dp = next; + d = *dp; + } +} + +/* Reset the updating flag. */ + +static void +reset_updating (const void *item) +{ + struct file *f = (struct file *) item; + f->updating = 0; +} + +/* For each dependency of each file, make the 'struct dep' point + at the appropriate 'struct file' (which may have to be created). + + Also mark the files depended on by .PRECIOUS, .PHONY, .SILENT, + and various other special targets. */ + +void +snap_deps (void) +{ + struct file *f; + struct file *f2; + struct dep *d; + + /* Remember that we've done this. Once we start snapping deps we can no + longer define new targets. */ + snapped_deps = 1; + +#ifdef CONFIG_WITH_2ND_TARGET_EXPANSION + /* Perform 2nd target expansion on files which requires this. This will + be re-inserting (delete+insert) hash table entries so we have to use + hash_dump(). */ + if (second_target_expansion) + { + struct file **file_slot_0, **file_end, **file_slot; +# ifdef KMK /* turn on warnings here. */ + int save = warn_undefined_variables_flag; + warn_undefined_variables_flag = 1; +# endif + + file_slot_0 = (struct file **) hash_dump (&files, 0, 0); + file_end = file_slot_0 + files.ht_fill; + for (file_slot = file_slot_0; file_slot < file_end; file_slot++) + for (f = *file_slot; f != 0; f = f->prev) + if (f->need_2nd_target_expansion) + do_2nd_target_expansion (f); + free (file_slot_0); + +# ifdef KMK + warn_undefined_variables_flag = save; +# endif + + /* Disable second target expansion now since we won't expand files + entered after this point. (Saves CPU cycles in enter_file()). */ + second_target_expansion = 0; + } +#endif /* CONFIG_WITH_2ND_TARGET_EXPANSION */ + +#ifdef CONFIG_WITH_INCLUDEDEP + /* Process any queued includedep files. Since includedep is supposed + to be *simple* stuff, we can do this after the second target expansion + and thereby save a little time. */ + incdep_flush_and_term (); +#endif /* CONFIG_WITH_INCLUDEDEP */ + + /* Perform second expansion and enter each dependency name as a file. We + must use hash_dump() here because within these loops we likely add new + files to the table, possibly causing an in-situ table expansion. + + We only need to do this if second_expansion has been defined; if it + hasn't then all deps were expanded as the makefile was read in. If we + ever change make to be able to unset .SECONDARY_EXPANSION this will have + to change. */ + + if (second_expansion) + { + struct file **file_slot_0 = (struct file **) hash_dump (&files, 0, 0); + struct file **file_end = file_slot_0 + files.ht_fill; + struct file **file_slot; + const char *suffixes; + + /* Expand .SUFFIXES: its prerequisites are used for $$* calc. */ + f = lookup_file (".SUFFIXES"); + suffixes = f ? f->name : 0; + for (; f != 0; f = f->prev) + expand_deps (f); + +#if 0 /* def KMK - not-parallel is a performance kill, but since double-colon is werid anyway, skip this hack. */ + /* This is a HACK to work around the still broken test #9 in + features/double_colon. It produces the wrong result if the build is + parallel because of changed evaluation order. Just make these + problematic rules execute in single field till a proper fix is + forthcomming... */ + + for (file_slot = file_slot_0; file_slot < file_end; file_slot++) + if ( (f = *file_slot) != 0 + && f->double_colon + && ( f->double_colon != f + || f->last != f)) + for (f2 = f->double_colon; f2 != 0; f2 = f2->prev) + f2->command_flags |= COMMANDS_NOTPARALLEL; +#endif /* KMK */ + + /* For every target that's not .SUFFIXES, expand its prerequisites. */ + + for (file_slot = file_slot_0; file_slot < file_end; file_slot++) + for (f = *file_slot; f != 0; f = f->prev) + if (f->name != suffixes) + expand_deps (f); + free (file_slot_0); + } + else + /* We're not doing second expansion, so reset updating. */ + hash_map (&files, reset_updating); + + /* Now manage all the special targets. */ + + for (f = lookup_file (".PRECIOUS"); f != 0; f = f->prev) + for (d = f->deps; d != 0; d = d->next) + for (f2 = d->file; f2 != 0; f2 = f2->prev) + f2->precious = 1; + + for (f = lookup_file (".LOW_RESOLUTION_TIME"); f != 0; f = f->prev) + for (d = f->deps; d != 0; d = d->next) + for (f2 = d->file; f2 != 0; f2 = f2->prev) + f2->low_resolution_time = 1; + + for (f = lookup_file (".PHONY"); f != 0; f = f->prev) + for (d = f->deps; d != 0; d = d->next) + for (f2 = d->file; f2 != 0; f2 = f2->prev) + { + /* Mark this file as phony nonexistent target. */ + f2->phony = 1; + f2->is_target = 1; + f2->last_mtime = NONEXISTENT_MTIME; + f2->mtime_before_update = NONEXISTENT_MTIME; + } + + for (f = lookup_file (".INTERMEDIATE"); f != 0; f = f->prev) + /* Mark .INTERMEDIATE deps as intermediate files. */ + for (d = f->deps; d != 0; d = d->next) + for (f2 = d->file; f2 != 0; f2 = f2->prev) + f2->intermediate = 1; + /* .INTERMEDIATE with no deps does nothing. + Marking all files as intermediates is useless since the goal targets + would be deleted after they are built. */ + + for (f = lookup_file (".SECONDARY"); f != 0; f = f->prev) + /* Mark .SECONDARY deps as both intermediate and secondary. */ + if (f->deps) + for (d = f->deps; d != 0; d = d->next) + for (f2 = d->file; f2 != 0; f2 = f2->prev) + f2->intermediate = f2->secondary = 1; + /* .SECONDARY with no deps listed marks *all* files that way. */ + else + { + all_secondary = 1; + hash_map (&files, set_intermediate); + } + + f = lookup_file (".EXPORT_ALL_VARIABLES"); + if (f != 0 && f->is_target) + export_all_variables = 1; + + f = lookup_file (".IGNORE"); + if (f != 0 && f->is_target) + { + if (f->deps == 0) + ignore_errors_flag = 1; + else + for (d = f->deps; d != 0; d = d->next) + for (f2 = d->file; f2 != 0; f2 = f2->prev) + f2->command_flags |= COMMANDS_NOERROR; + } + + f = lookup_file (".SILENT"); + if (f != 0 && f->is_target) + { + if (f->deps == 0) + silent_flag = 1; + else + for (d = f->deps; d != 0; d = d->next) + for (f2 = d->file; f2 != 0; f2 = f2->prev) + f2->command_flags |= COMMANDS_SILENT; + } + + f = lookup_file (".NOTPARALLEL"); + if (f != 0 && f->is_target) +#ifndef CONFIG_WITH_EXTENDED_NOTPARALLEL + not_parallel = 1; +#else /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ + { + if (f->deps == 0) + { + DB (DB_KMK, (_("not_parallel -1\n"))); + not_parallel = -1; + } + else + for (d = f->deps; d != 0; d = d->next) + for (f2 = d->file; f2 != 0; f2 = f2->prev) + f2->command_flags |= COMMANDS_NOTPARALLEL; + } +#endif /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ + +#ifndef NO_MINUS_C_MINUS_O + /* If .POSIX was defined, remove OUTPUT_OPTION to comply. */ + /* This needs more work: what if the user sets this in the makefile? + if (posix_pedantic) + define_variable_cname ("OUTPUT_OPTION", "", o_default, 1); + */ +#endif +} + +/* Set the 'command_state' member of FILE and all its 'also_make's. */ + +void +set_command_state (struct file *file, enum cmd_state state) +{ + struct dep *d; + + file->command_state = state; + + for (d = file->also_make; d != 0; d = d->next) + d->file->command_state = state; + +#ifdef CONFIG_WITH_EXPLICIT_MULTITARGET + if (file->multi_head) + for (file = file->multi_head; file != 0; file = file->multi_next) + file->command_state = state; +#endif +} + +/* Convert an external file timestamp to internal form. */ + +FILE_TIMESTAMP +file_timestamp_cons (const char *fname, time_t stamp, long int ns) +{ + int offset = ORDINARY_MTIME_MIN + (FILE_TIMESTAMP_HI_RES ? ns : 0); + FILE_TIMESTAMP s = stamp; + FILE_TIMESTAMP product = (FILE_TIMESTAMP) s << FILE_TIMESTAMP_LO_BITS; + FILE_TIMESTAMP ts = product + offset; + + if (! (s <= FILE_TIMESTAMP_S (ORDINARY_MTIME_MAX) + && product <= ts && ts <= ORDINARY_MTIME_MAX)) + { + char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1]; + const char *f = fname ? fname : _("Current time"); + ts = s <= OLD_MTIME ? ORDINARY_MTIME_MIN : ORDINARY_MTIME_MAX; + file_timestamp_sprintf (buf, ts); + OSS (error, NILF, + _("%s: Timestamp out of range; substituting %s"), f, buf); + } + + return ts; +} + +/* Return the current time as a file timestamp, setting *RESOLUTION to + its resolution. */ +FILE_TIMESTAMP +file_timestamp_now (int *resolution) +{ + int r; + time_t s; + int ns; + + /* Don't bother with high-resolution clocks if file timestamps have + only one-second resolution. The code below should work, but it's + not worth the hassle of debugging it on hosts where it fails. */ +#if FILE_TIMESTAMP_HI_RES +# if HAVE_CLOCK_GETTIME && defined CLOCK_REALTIME + { + struct timespec timespec; + if (clock_gettime (CLOCK_REALTIME, ×pec) == 0) + { + r = 1; + s = timespec.tv_sec; + ns = timespec.tv_nsec; + goto got_time; + } + } +# endif +# if HAVE_GETTIMEOFDAY + { + struct timeval timeval; + if (gettimeofday (&timeval, 0) == 0) + { + r = 1000; + s = timeval.tv_sec; + ns = timeval.tv_usec * 1000; + goto got_time; + } + } +# endif +#endif + + r = 1000000000; + s = time ((time_t *) 0); + ns = 0; + +#if FILE_TIMESTAMP_HI_RES + got_time: +#endif + *resolution = r; + return file_timestamp_cons (0, s, ns); +} + +/* Place into the buffer P a printable representation of the file + timestamp TS. */ +void +file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts) +{ + time_t t = FILE_TIMESTAMP_S (ts); + struct tm *tm = localtime (&t); + + if (tm) + sprintf (p, "%04d-%02d-%02d %02d:%02d:%02d", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (t < 0) + sprintf (p, "%ld", (long) t); + else + sprintf (p, "%lu", (unsigned long) t); + p += strlen (p); + + /* Append nanoseconds as a fraction, but remove trailing zeros. We don't + know the actual timestamp resolution, since clock_getres applies only to + local times, whereas this timestamp might come from a remote filesystem. + So removing trailing zeros is the best guess that we can do. */ + sprintf (p, ".%09d", FILE_TIMESTAMP_NS (ts)); + p += strlen (p) - 1; + while (*p == '0') + p--; + p += *p != '.'; + + *p = '\0'; +} + +/* Print the data base of files. */ + +void +print_prereqs (const struct dep *deps) +{ + const struct dep *ood = 0; + + /* Print all normal dependencies; note any order-only deps. */ + for (; deps != 0; deps = deps->next) + if (! deps->ignore_mtime) + printf (" %s", dep_name (deps)); + else if (! ood) + ood = deps; + + /* Print order-only deps, if we have any. */ + if (ood) + { + printf (" | %s", dep_name (ood)); + for (ood = ood->next; ood != 0; ood = ood->next) + if (ood->ignore_mtime) + printf (" %s", dep_name (ood)); + } + + putchar ('\n'); +} + +static void +print_file (const void *item) +{ + const struct file *f = item; + + /* If we're not using builtin targets, don't show them. + + Ideally we'd be able to delete them altogether but currently there's no + facility to ever delete a file once it's been added. */ + if (no_builtin_rules_flag && f->builtin) + return; + + putchar ('\n'); + + if (f->cmds && f->cmds->recipe_prefix != cmd_prefix) + { + fputs (".RECIPEPREFIX = ", stdout); + cmd_prefix = f->cmds->recipe_prefix; + if (cmd_prefix != RECIPEPREFIX_DEFAULT) + putchar (cmd_prefix); + putchar ('\n'); + } + + if (f->variables != 0) + print_target_variables (f); + + if (!f->is_target) + puts (_("# Not a target:")); +#ifdef CONFIG_WITH_EXPLICIT_MULTITARGET + if (f->multi_head) + { + const struct file *f2; + if (f->multi_head == f) + { + int multi_maybe = -1; + assert (!f->multi_maybe); + assert (!f->double_colon); + + printf ("%s", f->name); + for (f2 = f->multi_next; f2 != 0; f2 = f2->multi_next) + { + printf (" %s%s", f2->multi_maybe != multi_maybe + ? f2->multi_maybe ? "+| " : "+ " : "", + f2->name); + multi_maybe = f2->multi_maybe; + } + if (f->deps) + printf (": \\\n\t"); + else + putchar (':'); + } + else + printf ("%s:%s", f->name, f->double_colon ? ":" : ""); + } + else +#endif + printf ("%s:%s", f->name, f->double_colon ? ":" : ""); + + print_prereqs (f->deps); + +#ifdef CONFIG_WITH_EXPLICIT_MULTITARGET + if (f->multi_head && f->multi_head != f) + { + const struct file *f2; + fputs (_("# In multi target list:"), stdout); + for (f2 = f->multi_head; f2 != 0; f2 = f2->multi_next) + printf (" %s%s", f2->name, f == f2 ? "(*)" : ""); + putchar ('\n'); + if (f->multi_maybe) + puts (_("# File is an optional multi target member.")); + } +#endif + + if (f->precious) + puts (_("# Precious file (prerequisite of .PRECIOUS).")); + if (f->phony) + puts (_("# Phony target (prerequisite of .PHONY).")); + if (f->cmd_target) + puts (_("# Command line target.")); + if (f->dontcare) + puts (_("# A default, MAKEFILES, or -include/sinclude makefile.")); +#if defined (CONFIG_WITH_COMPILER) || defined (CONFIG_WITH_MAKE_STATS) + if (f->eval_count > 0) + { +# ifdef CONFIG_WITH_COMPILER + if (f->evalprog) + printf (_("# Makefile evaluated %u times - compiled\n"), f->eval_count); + else +# endif + printf (_("# Makefile evaluated %u times\n"), f->eval_count); + } +#endif + if (f->builtin) + puts (_("# Builtin rule")); + puts (f->tried_implicit + ? _("# Implicit rule search has been done.") + : _("# Implicit rule search has not been done.")); + if (f->stem != 0) + printf (_("# Implicit/static pattern stem: '%s'\n"), f->stem); + if (f->intermediate) + puts (_("# File is an intermediate prerequisite.")); + if (f->also_make != 0) + { + const struct dep *d; + fputs (_("# Also makes:"), stdout); + for (d = f->also_make; d != 0; d = d->next) + printf (" %s", dep_name (d)); + putchar ('\n'); + } + if (f->last_mtime == UNKNOWN_MTIME) + puts (_("# Modification time never checked.")); + else if (f->last_mtime == NONEXISTENT_MTIME) + puts (_("# File does not exist.")); + else if (f->last_mtime == OLD_MTIME) + puts (_("# File is very old.")); + else + { + char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1]; + file_timestamp_sprintf (buf, f->last_mtime); + printf (_("# Last modified %s\n"), buf); + } + puts (f->updated + ? _("# File has been updated.") : _("# File has not been updated.")); + switch (f->command_state) + { + case cs_running: + puts (_("# Recipe currently running (THIS IS A BUG).")); + break; + case cs_deps_running: + puts (_("# Dependencies recipe running (THIS IS A BUG).")); + break; + case cs_not_started: + case cs_finished: + switch (f->update_status) + { + case us_none: + break; + case us_success: + puts (_("# Successfully updated.")); + break; + case us_question: + assert (question_flag); + puts (_("# Needs to be updated (-q is set).")); + break; + case us_failed: + puts (_("# Failed to be updated.")); + break; + } + break; + default: + puts (_("# Invalid value in 'command_state' member!")); + fflush (stdout); + fflush (stderr); + abort (); + } + + if (f->variables != 0) + print_file_variables (f); + + if (f->cmds != 0) + print_commands (f->cmds); + + if (f->prev) + print_file ((const void *) f->prev); +} + +void +print_file_data_base (void) +{ + puts (_("\n# Files")); + + hash_map (&files, print_file); + + fputs (_("\n# files hash-table stats:\n# "), stdout); + hash_print_stats (&files, stdout); +} + +#ifdef CONFIG_WITH_PRINT_STATS_SWITCH +void +print_file_stats (void) +{ + fputs (_("\n# files hash-table stats:\n# "), stdout); + hash_print_stats (&files, stdout); + fputs ("\n", stdout); +} +#endif + +/* Verify the integrity of the data base of files. */ + +#define VERIFY_CACHED(_p,_n) \ + do{ \ + if (_p->_n && _p->_n[0] && !strcache_iscached (_p->_n)) \ + error (NULL, strlen (_p->name) + CSTRLEN (# _n) + strlen (_p->_n), \ + _("%s: Field '%s' not cached: %s"), _p->name, # _n, _p->_n); \ + }while(0) + +static void +verify_file (const void *item) +{ + const struct file *f = item; + const struct dep *d; + + VERIFY_CACHED (f, name); + VERIFY_CACHED (f, hname); + VERIFY_CACHED (f, vpath); + VERIFY_CACHED (f, stem); + + /* Check the deps. */ + for (d = f->deps; d != 0; d = d->next) + { + if (! d->need_2nd_expansion) + VERIFY_CACHED (d, name); + VERIFY_CACHED (d, stem); + } +} + +void +verify_file_data_base (void) +{ + hash_map (&files, verify_file); +} + +#define EXPANSION_INCREMENT(_l) ((((_l) / 500) + 1) * 500) + +char * +build_target_list (char *value) +{ + static unsigned long last_targ_count = 0; + + if (files.ht_fill != last_targ_count) + { + unsigned long max = EXPANSION_INCREMENT (strlen (value)); + unsigned long len; + char *p; + struct file **fp = (struct file **) files.ht_vec; + struct file **end = &fp[files.ht_size]; + + /* Make sure we have at least MAX bytes in the allocated buffer. */ + value = xrealloc (value, max); + + p = value; + len = 0; + for (; fp < end; ++fp) + if (!HASH_VACANT (*fp) && (*fp)->is_target) + { + struct file *f = *fp; + int l = strlen (f->name); + + len += l + 1; + if (len > max) + { + unsigned long off = p - value; + + max += EXPANSION_INCREMENT (l + 1); + value = xrealloc (value, max); + p = &value[off]; + } + + memcpy (p, f->name, l); + p += l; + *(p++) = ' '; + } + *(p-1) = '\0'; + + last_targ_count = files.ht_fill; + } + + return value; +} + +void +init_hash_files (void) +{ +#ifndef CONFIG_WITH_STRCACHE2 +# ifdef KMK + hash_init (&files, /*65535*/ 32755, file_hash_1, file_hash_2, file_hash_cmp); +# else + hash_init (&files, 1000, file_hash_1, file_hash_2, file_hash_cmp); +# endif +#else /* CONFIG_WITH_STRCACHE2 */ +# ifdef KMK + hash_init_strcached (&files, 32755, &file_strcache, + offsetof (struct file, hname)); +# else + hash_init_strcached (&files, 1000, &file_strcache, + offsetof (struct file, hname)); +# endif +#endif /* CONFIG_WITH_STRCACHE2 */ +} + +/* EOF */ diff --git a/src/kmk/filedef.h b/src/kmk/filedef.h new file mode 100644 index 0000000..cf606ce --- /dev/null +++ b/src/kmk/filedef.h @@ -0,0 +1,254 @@ +/* Definition of target file data structures for GNU Make. +Copyright (C) 1988-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + + +/* Structure that represents the info on one file + that the makefile says how to make. + All of these are chained together through 'next'. */ + +#include "hash.h" + +struct file + { + const char *name; + const char *hname; /* Hashed filename */ + const char *vpath; /* VPATH/vpath pathname */ + struct dep *deps; /* all dependencies, including duplicates */ +#ifdef CONFIG_WITH_LAZY_DEPS_VARS + struct dep *deps_no_dupes; /* dependencies without duplicates, created on + demaned by func_deps. */ +#endif + struct commands *cmds; /* Commands to execute for this target. */ + const char *stem; /* Implicit stem, if an implicit + rule has been used */ + struct dep *also_make; /* Targets that are made by making this. */ + struct file *prev; /* Previous entry for same file name; + used when there are multiple double-colon + entries for the same file. */ + struct file *last; /* Last entry for the same file name. */ + + /* File that this file was renamed to. After any time that a + file could be renamed, call 'check_renamed' (below). */ + struct file *renamed; + + /* List of variable sets used for this file. */ + struct variable_set_list *variables; + + /* Pattern-specific variable reference for this target, or null if there + isn't one. Also see the pat_searched flag, below. */ + struct variable_set_list *pat_variables; + + /* Immediate dependent that caused this target to be remade, + or nil if there isn't one. */ + struct file *parent; + + /* For a double-colon entry, this is the first double-colon entry for + the same file. Otherwise this is null. */ + struct file *double_colon; + +#ifdef CONFIG_WITH_EXPLICIT_MULTITARGET + /* For a target of an explicit multi target rule, this points to the + primary target. Otherwise this is null. */ + struct file *multi_head; + /* Pointer to next target of an explicit multi target rule. */ + struct file *multi_next; +#endif + +#ifdef CONFIG_WITH_COMPILER + struct kmk_cc_evalprog *evalprog; /* Pointer to evalval/evalctx "program". */ +#endif + + FILE_TIMESTAMP last_mtime; /* File's modtime, if already known. */ + FILE_TIMESTAMP mtime_before_update; /* File's modtime before any updating + has been performed. */ + unsigned int considered; /* equal to 'considered' if file has been + considered on current scan of goal chain */ + int command_flags; /* Flags OR'd in for cmds; see commands.h. */ + enum update_status /* Status of the last attempt to update. */ + { + us_success = 0, /* Successfully updated. Must be 0! */ + us_none, /* No attempt to update has been made. */ + us_question, /* Needs to be updated (-q is is set). */ + us_failed /* Update failed. */ + } update_status ENUM_BITFIELD (2); + enum cmd_state /* State of the commands. */ + { + cs_not_started = 0, /* Not yet started. Must be 0! */ + cs_deps_running, /* Dep commands running. */ + cs_running, /* Commands running. */ + cs_finished /* Commands finished. */ + } command_state ENUM_BITFIELD (2); + + unsigned int builtin:1; /* True if the file is a builtin rule. */ + unsigned int precious:1; /* Non-0 means don't delete file on quit */ + unsigned int loaded:1; /* True if the file is a loaded object. */ + unsigned int low_resolution_time:1; /* Nonzero if this file's time stamp + has only one-second resolution. */ + unsigned int tried_implicit:1; /* Nonzero if have searched + for implicit rule for making + this file; don't search again. */ + unsigned int updating:1; /* Nonzero while updating deps of this file */ + unsigned int updated:1; /* Nonzero if this file has been remade. */ + unsigned int is_target:1; /* Nonzero if file is described as target. */ + unsigned int cmd_target:1; /* Nonzero if file was given on cmd line. */ + unsigned int phony:1; /* Nonzero if this is a phony file + i.e., a prerequisite of .PHONY. */ + unsigned int intermediate:1;/* Nonzero if this is an intermediate file. */ + unsigned int secondary:1; /* Nonzero means remove_intermediates should + not delete it. */ + unsigned int dontcare:1; /* Nonzero if no complaint is to be made if + this target cannot be remade. */ + unsigned int ignore_vpath:1;/* Nonzero if we threw out VPATH name. */ + unsigned int pat_searched:1;/* Nonzero if we already searched for + pattern-specific variables. */ + unsigned int no_diag:1; /* True if the file failed to update and no + diagnostics has been issued (dontcare). */ + +#ifdef CONFIG_WITH_EXPLICIT_MULTITARGET + unsigned int multi_maybe:1; /* Nonzero if this file isn't always updated + by the explicit multi target rule. */ +#endif +#ifdef CONFIG_WITH_2ND_TARGET_EXPANSION + unsigned int need_2nd_target_expansion:1; /* Nonzero if this file needs + second expansion of its name. Whether it + can receive this is decided at parse time, + and the expanding done in snap_deps. */ +#endif +#if defined (CONFIG_WITH_COMPILER) || defined (CONFIG_WITH_MAKE_STATS) + unsigned int eval_count:14; /* Times evaluated as a makefile. */ +#endif + }; + + +extern struct file *default_file; + + +struct file *lookup_file (const char *name); +#ifdef CONFIG_WITH_STRCACHE2 +struct file *lookup_file_cached (const char *name); +#endif +struct file *enter_file (const char *name); +struct dep *split_prereqs (char *prereqstr); +struct dep *enter_prereqs (struct dep *prereqs, const char *stem); +void remove_intermediates (int sig); +void snap_deps (void); +void rename_file (struct file *file, const char *name); +void rehash_file (struct file *file, const char *name); +void set_command_state (struct file *file, enum cmd_state state); +void notice_finished_file (struct file *file); +void init_hash_files (void); +void verify_file_data_base (void); +char *build_target_list (char *old_list); +void print_prereqs (const struct dep *deps); +void print_file_data_base (void); +int try_implicit_rule (struct file *file, unsigned int depth); +int stemlen_compare (const void *v1, const void *v2); + +#if FILE_TIMESTAMP_HI_RES +# define FILE_TIMESTAMP_STAT_MODTIME(fname, st) \ + file_timestamp_cons (fname, (st).st_mtime, (st).ST_MTIM_NSEC) +#else +# define FILE_TIMESTAMP_STAT_MODTIME(fname, st) \ + file_timestamp_cons (fname, (st).st_mtime, 0) +#endif + +/* If FILE_TIMESTAMP is 64 bits (or more), use nanosecond resolution. + (Multiply by 2**30 instead of by 10**9 to save time at the cost of + slightly decreasing the number of available timestamps.) With + 64-bit FILE_TIMESTAMP, this stops working on 2514-05-30 01:53:04 + UTC, but by then uintmax_t should be larger than 64 bits. */ +#define FILE_TIMESTAMPS_PER_S (FILE_TIMESTAMP_HI_RES ? 1000000000 : 1) +#define FILE_TIMESTAMP_LO_BITS (FILE_TIMESTAMP_HI_RES ? 30 : 0) + +#define FILE_TIMESTAMP_S(ts) (((ts) - ORDINARY_MTIME_MIN) \ + >> FILE_TIMESTAMP_LO_BITS) +#define FILE_TIMESTAMP_NS(ts) ((int) (((ts) - ORDINARY_MTIME_MIN) \ + & ((1 << FILE_TIMESTAMP_LO_BITS) - 1))) + +/* Upper bound on length of string "YYYY-MM-DD HH:MM:SS.NNNNNNNNN" + representing a file timestamp. The upper bound is not necessarily 29, + since the year might be less than -999 or greater than 9999. + + Subtract one for the sign bit if in case file timestamps can be negative; + subtract FLOOR_LOG2_SECONDS_PER_YEAR to yield an upper bound on how many + file timestamp bits might affect the year; + 302 / 1000 is log10 (2) rounded up; + add one for integer division truncation; + add one more for a minus sign if file timestamps can be negative; + add 4 to allow for any 4-digit epoch year (e.g. 1970); + add 25 to allow for "-MM-DD HH:MM:SS.NNNNNNNNN". */ +#define FLOOR_LOG2_SECONDS_PER_YEAR 24 +#define FILE_TIMESTAMP_PRINT_LEN_BOUND \ + (((sizeof (FILE_TIMESTAMP) * CHAR_BIT - 1 - FLOOR_LOG2_SECONDS_PER_YEAR) \ + * 302 / 1000) \ + + 1 + 1 + 4 + 25) + +FILE_TIMESTAMP file_timestamp_cons (char const *, time_t, long int); +FILE_TIMESTAMP file_timestamp_now (int *); +void file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts); + +/* Return the mtime of file F (a struct file *), caching it. + The value is NONEXISTENT_MTIME if the file does not exist. */ +#define file_mtime(f) file_mtime_1 ((f), 1) +/* Return the mtime of file F (a struct file *), caching it. + Don't search using vpath for the file--if it doesn't actually exist, + we don't find it. + The value is NONEXISTENT_MTIME if the file does not exist. */ +#define file_mtime_no_search(f) file_mtime_1 ((f), 0) +FILE_TIMESTAMP f_mtime (struct file *file, int search); +#define file_mtime_1(f, v) \ + ((f)->last_mtime == UNKNOWN_MTIME ? f_mtime ((f), v) : (f)->last_mtime) + +/* Special timestamp values. */ + +/* The file's timestamp is not yet known. */ +#define UNKNOWN_MTIME 0 + +/* The file does not exist. */ +#define NONEXISTENT_MTIME 1 + +/* The file does not exist, and we assume that it is older than any + actual file. */ +#define OLD_MTIME 2 + +/* The smallest and largest ordinary timestamps. */ +#define ORDINARY_MTIME_MIN (OLD_MTIME + 1) +#if FILE_TIMESTAMP_HI_RES == 0 /* bird: shut up annoying warnings! + ASSUMES: unsigned FILE_TIMESTAMP ++. */ +# define ORDINARY_MTIME_MAX ( ~ (FILE_TIMESTAMP) 0 ) +#else +#define ORDINARY_MTIME_MAX ((FILE_TIMESTAMP_S (NEW_MTIME) \ + << FILE_TIMESTAMP_LO_BITS) \ + + ORDINARY_MTIME_MIN + FILE_TIMESTAMPS_PER_S - 1) +#endif + +/* Modtime value to use for 'infinitely new'. We used to get the current time + from the system and use that whenever we wanted 'new'. But that causes + trouble when the machine running make and the machine holding a file have + different ideas about what time it is; and can also lose for 'force' + targets, which need to be considered newer than anything that depends on + them, even if said dependents' modtimes are in the future. */ +#if 1 /* bird: ASSUME the type is unsigned and the wrath of a pedantic gcc. */ +# define NEW_MTIME ( ~ (FILE_TIMESTAMP) 0 ) +#else +#define NEW_MTIME INTEGER_TYPE_MAXIMUM (FILE_TIMESTAMP) +#endif + +#define check_renamed(file) \ + while ((file)->renamed != 0) (file) = (file)->renamed /* No ; here. */ + +/* Have we snapped deps yet? */ +extern int snapped_deps; diff --git a/src/kmk/function.c b/src/kmk/function.c new file mode 100644 index 0000000..5ad8586 --- /dev/null +++ b/src/kmk/function.c @@ -0,0 +1,8250 @@ +/* Builtin function expansion for GNU Make. +Copyright (C) 1988-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#include "makeint.h" +#include "filedef.h" +#include "variable.h" +#include "dep.h" +#include "job.h" +#include "commands.h" +#include "debug.h" + +#ifdef _AMIGA +#include "amiga.h" +#endif + +#ifdef WINDOWS32 /* bird */ +# include "pathstuff.h" +# ifdef CONFIG_NEW_WIN_CHILDREN +# include "w32/winchildren.h" +# endif +#endif + +#ifdef KMK_HELPERS +# include "kbuild.h" +#endif +#ifdef CONFIG_WITH_PRINTF +# include "kmkbuiltin.h" +#endif +#ifdef CONFIG_WITH_XARGS /* bird */ +# ifdef HAVE_LIMITS_H +# include +# endif +#endif +#ifdef CONFIG_WITH_COMPILER +# include "kmk_cc_exec.h" +#endif +#include /* bird */ + +#if defined (CONFIG_WITH_MATH) || defined (CONFIG_WITH_NANOTS) || defined (CONFIG_WITH_FILE_SIZE) /* bird */ +# include +typedef big_int math_int; +static char *math_int_to_variable_buffer (char *, math_int); +static math_int math_int_from_string (const char *str); +#endif + +#ifdef CONFIG_WITH_NANOTS /* bird */ +# ifdef WINDOWS32 +# include +# endif +#endif + +#ifdef __OS2__ +# define CONFIG_WITH_OS2_LIBPATH 1 +#endif +#ifdef CONFIG_WITH_OS2_LIBPATH +# define INCL_BASE +# define INCL_ERRROS +# include + +# define QHINF_EXEINFO 1 /* NE exeinfo. */ +# define QHINF_READRSRCTBL 2 /* Reads from the resource table. */ +# define QHINF_READFILE 3 /* Reads from the executable file. */ +# define QHINF_LIBPATHLENGTH 4 /* Gets the libpath length. */ +# define QHINF_LIBPATH 5 /* Gets the entire libpath. */ +# define QHINF_FIXENTRY 6 /* NE only */ +# define QHINF_STE 7 /* NE only */ +# define QHINF_MAPSEL 8 /* NE only */ + extern APIRET APIENTRY DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbBuffer, ULONG ulSubFunction); +#endif /* CONFIG_WITH_OS2_LIBPATH */ + +#if defined(KMK) || defined(CONFIG_WITH_LAZY_DEPS_VARS) +/** Checks if the @a_cch characters (bytes) in @a a_psz equals @a a_szConst. */ +# define STR_N_EQUALS(a_psz, a_cch, a_szConst) \ + ( (a_cch) == sizeof (a_szConst) - 1 && !strncmp ((a_psz), (a_szConst), sizeof (a_szConst) - 1) ) +#endif + +#ifdef KMK +# ifdef _MSC_VER +# include "kmkbuiltin/mscfakes.h" +# endif +# include "version_compare.h" +#endif + + +struct function_table_entry + { + union { + char *(*func_ptr) (char *output, char **argv, const char *fname); + gmk_func_ptr alloc_func_ptr; + } fptr; + const char *name; + unsigned char len; + unsigned char minimum_args; + unsigned char maximum_args; + unsigned char expand_args:1; + unsigned char alloc_fn:1; + }; + +static unsigned long +function_table_entry_hash_1 (const void *keyv) +{ + const struct function_table_entry *key = keyv; + return_STRING_N_HASH_1 (key->name, key->len); +} + +static unsigned long +function_table_entry_hash_2 (const void *keyv) +{ + const struct function_table_entry *key = keyv; + return_STRING_N_HASH_2 (key->name, key->len); +} + +static int +function_table_entry_hash_cmp (const void *xv, const void *yv) +{ + const struct function_table_entry *x = xv; + const struct function_table_entry *y = yv; + int result = x->len - y->len; + if (result) + return result; + return_STRING_N_COMPARE (x->name, y->name, x->len); +} + +static struct hash_table function_table; + +#ifdef CONFIG_WITH_MAKE_STATS +long make_stats_allocations = 0; +long make_stats_reallocations = 0; +unsigned long make_stats_allocated = 0; +unsigned long make_stats_ht_lookups = 0; +unsigned long make_stats_ht_collisions = 0; +#endif + + +/* Store into VARIABLE_BUFFER at O the result of scanning TEXT and replacing + each occurrence of SUBST with REPLACE. TEXT is null-terminated. SLEN is + the length of SUBST and RLEN is the length of REPLACE. If BY_WORD is + nonzero, substitutions are done only on matches which are complete + whitespace-delimited words. */ + +char * +subst_expand (char *o, const char *text, const char *subst, const char *replace, + unsigned int slen, unsigned int rlen, int by_word) +{ + const char *t = text; + const char *p; + + if (slen == 0 && !by_word) + { + /* The first occurrence of "" in any string is its end. */ + o = variable_buffer_output (o, t, strlen (t)); + if (rlen > 0) + o = variable_buffer_output (o, replace, rlen); + return o; + } + + do + { + if (by_word && slen == 0) + /* When matching by words, the empty string should match + the end of each word, rather than the end of the whole text. */ + p = end_of_token (next_token (t)); + else + { + p = strstr (t, subst); + if (p == 0) + { + /* No more matches. Output everything left on the end. */ + o = variable_buffer_output (o, t, strlen (t)); + return o; + } + } + + /* Output everything before this occurrence of the string to replace. */ + if (p > t) + o = variable_buffer_output (o, t, p - t); + + /* If we're substituting only by fully matched words, + or only at the ends of words, check that this case qualifies. */ + if (by_word + && ((p > text && !ISSPACE (p[-1])) + || ! STOP_SET (p[slen], MAP_SPACE|MAP_NUL))) + /* Struck out. Output the rest of the string that is + no longer to be replaced. */ + o = variable_buffer_output (o, subst, slen); + else if (rlen > 0) + /* Output the replacement string. */ + o = variable_buffer_output (o, replace, rlen); + + /* Advance T past the string to be replaced. */ + t = p + slen; + } while (*t != '\0'); + + return o; +} + + +/* Store into VARIABLE_BUFFER at O the result of scanning TEXT + and replacing strings matching PATTERN with REPLACE. + If PATTERN_PERCENT is not nil, PATTERN has already been + run through find_percent, and PATTERN_PERCENT is the result. + If REPLACE_PERCENT is not nil, REPLACE has already been + run through find_percent, and REPLACE_PERCENT is the result. + Note that we expect PATTERN_PERCENT and REPLACE_PERCENT to point to the + character _AFTER_ the %, not to the % itself. +*/ + +char * +patsubst_expand_pat (char *o, const char *text, + const char *pattern, const char *replace, + const char *pattern_percent, const char *replace_percent) +{ + unsigned int pattern_prepercent_len, pattern_postpercent_len; + unsigned int replace_prepercent_len, replace_postpercent_len; + const char *t; + unsigned int len; + int doneany = 0; + + /* Record the length of REPLACE before and after the % so we don't have to + compute these lengths more than once. */ + if (replace_percent) + { + replace_prepercent_len = replace_percent - replace - 1; + replace_postpercent_len = strlen (replace_percent); + } + else + { + replace_prepercent_len = strlen (replace); + replace_postpercent_len = 0; + } + + if (!pattern_percent) + /* With no % in the pattern, this is just a simple substitution. */ + return subst_expand (o, text, pattern, replace, + strlen (pattern), strlen (replace), 1); + + /* Record the length of PATTERN before and after the % + so we don't have to compute it more than once. */ + pattern_prepercent_len = pattern_percent - pattern - 1; + pattern_postpercent_len = strlen (pattern_percent); + + while ((t = find_next_token (&text, &len)) != 0) + { + int fail = 0; + + /* Is it big enough to match? */ + if (len < pattern_prepercent_len + pattern_postpercent_len) + fail = 1; + + /* Does the prefix match? */ + if (!fail && pattern_prepercent_len > 0 + && (*t != *pattern + || t[pattern_prepercent_len - 1] != pattern_percent[-2] + || !strneq (t + 1, pattern + 1, pattern_prepercent_len - 1))) + fail = 1; + + /* Does the suffix match? */ + if (!fail && pattern_postpercent_len > 0 + && (t[len - 1] != pattern_percent[pattern_postpercent_len - 1] + || t[len - pattern_postpercent_len] != *pattern_percent + || !strneq (&t[len - pattern_postpercent_len], + pattern_percent, pattern_postpercent_len - 1))) + fail = 1; + + if (fail) + /* It didn't match. Output the string. */ + o = variable_buffer_output (o, t, len); + else + { + /* It matched. Output the replacement. */ + + /* Output the part of the replacement before the %. */ + o = variable_buffer_output (o, replace, replace_prepercent_len); + + if (replace_percent != 0) + { + /* Output the part of the matched string that + matched the % in the pattern. */ + o = variable_buffer_output (o, t + pattern_prepercent_len, + len - (pattern_prepercent_len + + pattern_postpercent_len)); + /* Output the part of the replacement after the %. */ + o = variable_buffer_output (o, replace_percent, + replace_postpercent_len); + } + } + + /* Output a space, but not if the replacement is "". */ + if (fail || replace_prepercent_len > 0 + || (replace_percent != 0 && len + replace_postpercent_len > 0)) + { + o = variable_buffer_output (o, " ", 1); + doneany = 1; + } + } +#ifndef CONFIG_WITH_VALUE_LENGTH + if (doneany) + /* Kill the last space. */ + --o; +#else + /* Kill the last space and make sure there is a terminator there + so that strcache_add_len doesn't have to do a lot of exacty work + when expand_deps sends the output its way. */ + if (doneany) + *--o = '\0'; + else + o = variable_buffer_output (o, "\0", 1) - 1; +#endif + + return o; +} + +/* Store into VARIABLE_BUFFER at O the result of scanning TEXT + and replacing strings matching PATTERN with REPLACE. + If PATTERN_PERCENT is not nil, PATTERN has already been + run through find_percent, and PATTERN_PERCENT is the result. + If REPLACE_PERCENT is not nil, REPLACE has already been + run through find_percent, and REPLACE_PERCENT is the result. + Note that we expect PATTERN_PERCENT and REPLACE_PERCENT to point to the + character _AFTER_ the %, not to the % itself. +*/ + +char * +patsubst_expand (char *o, const char *text, char *pattern, char *replace) +{ + const char *pattern_percent = find_percent (pattern); + const char *replace_percent = find_percent (replace); + + /* If there's a percent in the pattern or replacement skip it. */ + if (replace_percent) + ++replace_percent; + if (pattern_percent) + ++pattern_percent; + + return patsubst_expand_pat (o, text, pattern, replace, + pattern_percent, replace_percent); +} + +#if defined (CONFIG_WITH_OPTIMIZATION_HACKS) || defined (CONFIG_WITH_VALUE_LENGTH) + +/* Char map containing the valid function name characters. */ +char func_char_map[256]; + +/* Do the hash table lookup. */ + +MY_INLINE const struct function_table_entry * +lookup_function_in_hash_tab (const char *s, unsigned char len) +{ + struct function_table_entry function_table_entry_key; + function_table_entry_key.name = s; + function_table_entry_key.len = len; + + return hash_find_item (&function_table, &function_table_entry_key); +} + +/* Look up a function by name. */ + +MY_INLINE const struct function_table_entry * +lookup_function (const char *s, unsigned int len) +{ + unsigned char ch; +# if 0 /* insane loop unroll */ + + if (len > MAX_FUNCTION_LENGTH) + len = MAX_FUNCTION_LENGTH + 1; + +# define X(idx) \ + if (!func_char_map[ch = s[idx]]) \ + { \ + if (ISBLANK (ch)) \ + return lookup_function_in_hash_tab (s, idx); \ + return 0; \ + } +# define Z(idx) \ + return lookup_function_in_hash_tab (s, idx); + + switch (len) + { + default: + assert (0); + case 0: return 0; + case 1: return 0; + case 2: X(0); X(1); Z(2); + case 3: X(0); X(1); X(2); Z(3); + case 4: X(0); X(1); X(2); X(3); Z(4); + case 5: X(0); X(1); X(2); X(3); X(4); Z(5); + case 6: X(0); X(1); X(2); X(3); X(4); X(5); Z(6); + case 7: X(0); X(1); X(2); X(3); X(4); X(5); X(6); Z(7); + case 8: X(0); X(1); X(2); X(3); X(4); X(5); X(6); X(7); Z(8); + case 9: X(0); X(1); X(2); X(3); X(4); X(5); X(6); X(7); X(8); Z(9); + case 10: X(0); X(1); X(2); X(3); X(4); X(5); X(6); X(7); X(8); X(9); Z(10); + case 11: X(0); X(1); X(2); X(3); X(4); X(5); X(6); X(7); X(8); X(9); X(10); Z(11); + case 12: X(0); X(1); X(2); X(3); X(4); X(5); X(6); X(7); X(8); X(9); X(10); X(11); Z(12); + case 13: X(0); X(1); X(2); X(3); X(4); X(5); X(6); X(7); X(8); X(9); X(10); X(11); X(12); + if ((ch = s[12]) == '\0' || ISBLANK (ch)) + return lookup_function_in_hash_tab (s, 12); + return 0; + } +# undef Z +# undef X + +# else /* normal loop */ + const char *e = s; + if (len > MAX_FUNCTION_LENGTH) + len = MAX_FUNCTION_LENGTH; + while (func_char_map[ch = *e]) + { + if (!len--) + return 0; + e++; + } + if (ch == '\0' || ISBLANK (ch)) + return lookup_function_in_hash_tab (s, e - s); + return 0; +# endif /* normal loop */ +} + +#else /* original code */ +/* Look up a function by name. */ + +static const struct function_table_entry * +lookup_function (const char *s) +{ + struct function_table_entry function_table_entry_key; + const char *e = s; + while (STOP_SET (*e, MAP_USERFUNC)) + e++; + + if (e == s || !STOP_SET(*e, MAP_NUL|MAP_SPACE)) + return NULL; + + function_table_entry_key.name = s; + function_table_entry_key.len = e - s; + + return hash_find_item (&function_table, &function_table_entry_key); +} +#endif /* original code */ + + +/* Return 1 if PATTERN matches STR, 0 if not. */ + +int +pattern_matches (const char *pattern, const char *percent, const char *str) +{ + unsigned int sfxlen, strlength; + + if (percent == 0) + { + unsigned int len = strlen (pattern) + 1; + char *new_chars = alloca (len); + memcpy (new_chars, pattern, len); + percent = find_percent (new_chars); + if (percent == 0) + return streq (new_chars, str); + pattern = new_chars; + } + + sfxlen = strlen (percent + 1); + strlength = strlen (str); + + if (strlength < (percent - pattern) + sfxlen + || !strneq (pattern, str, percent - pattern)) + return 0; + + return !strcmp (percent + 1, str + (strlength - sfxlen)); +} + +#ifdef KMK +/* Return 1 if PATTERN matches STR, 0 if not. + + PATTERN is the pattern to match against. PERCENT points to the '%' wildcard + inside PATTERN. SFXLEN is the length of pattern following PERCENT. */ + +static int +pattern_matches_ex (const char *pattern, const char *percent, + unsigned int sfxlen, + const char *str, unsigned int strlength) +{ + if (strlength < (percent - pattern) + sfxlen + || !strneq (pattern, str, percent - pattern) + || strcmp (percent + 1, str + (strlength - sfxlen))) + return 0; + return 1; +} +#endif + + +/* Find the next comma or ENDPAREN (counting nested STARTPAREN and + ENDPARENtheses), starting at PTR before END. Return a pointer to + next character. + + If no next argument is found, return NULL. +*/ + +static char * +find_next_argument (char startparen, char endparen, + const char *ptr, const char *end) +{ + int count = 0; + + for (; ptr < end; ++ptr) + if (*ptr == startparen) + ++count; + + else if (*ptr == endparen) + { + --count; + if (count < 0) + return NULL; + } + + else if (*ptr == ',' && !count) + return (char *)ptr; + + /* We didn't find anything. */ + return NULL; +} + + +/* Glob-expand LINE. The returned pointer is + only good until the next call to string_glob. */ + +static char * +string_glob (char *line) +{ + static char *result = 0; + static unsigned int length; + struct nameseq *chain; + unsigned int idx; + + chain = PARSE_FILE_SEQ (&line, struct nameseq, MAP_NUL, NULL, + /* We do not want parse_file_seq to strip './'s. + That would break examples like: + $(patsubst ./%.c,obj/%.o,$(wildcard ./?*.c)). */ + PARSEFS_NOSTRIP|PARSEFS_NOCACHE|PARSEFS_EXISTS); + + if (result == 0) + { + length = 100; + result = xmalloc (100); + } + + idx = 0; + while (chain != 0) + { + struct nameseq *next = chain->next; + unsigned int len = strlen (chain->name); + + if (idx + len + 1 > length) + { + length += (len + 1) * 2; + result = xrealloc (result, length); + } + memcpy (&result[idx], chain->name, len); + idx += len; + result[idx++] = ' '; + + /* Because we used PARSEFS_NOCACHE above, we have to free() NAME. */ + free ((char *)chain->name); +#ifndef CONFIG_WITH_ALLOC_CACHES + free (chain); +#else + alloccache_free (&nameseq_cache, chain); +#endif + chain = next; + } + + /* Kill the last space and terminate the string. */ + if (idx == 0) + result[0] = '\0'; + else + result[idx - 1] = '\0'; + + return result; +} + +/* + Builtin functions + */ + +static char * +func_patsubst (char *o, char **argv, const char *funcname UNUSED) +{ + o = patsubst_expand (o, argv[2], argv[0], argv[1]); + return o; +} + + +static char * +func_join (char *o, char **argv, const char *funcname UNUSED) +{ + int doneany = 0; + + /* Write each word of the first argument directly followed + by the corresponding word of the second argument. + If the two arguments have a different number of words, + the excess words are just output separated by blanks. */ + const char *tp; + const char *pp; + const char *list1_iterator = argv[0]; + const char *list2_iterator = argv[1]; + do + { + unsigned int len1, len2; + + tp = find_next_token (&list1_iterator, &len1); + if (tp != 0) + o = variable_buffer_output (o, tp, len1); + + pp = find_next_token (&list2_iterator, &len2); + if (pp != 0) + o = variable_buffer_output (o, pp, len2); + + if (tp != 0 || pp != 0) + { + o = variable_buffer_output (o, " ", 1); + doneany = 1; + } + } + while (tp != 0 || pp != 0); + if (doneany) + /* Kill the last blank. */ + --o; + + return o; +} + + +static char * +func_origin (char *o, char **argv, const char *funcname UNUSED) +{ + /* Expand the argument. */ + struct variable *v = lookup_variable (argv[0], strlen (argv[0])); + if (v == 0) + o = variable_buffer_output (o, "undefined", 9); + else + switch (v->origin) + { + default: + case o_invalid: + abort (); + break; + case o_default: + o = variable_buffer_output (o, "default", 7); + break; + case o_env: + o = variable_buffer_output (o, "environment", 11); + break; + case o_file: + o = variable_buffer_output (o, "file", 4); + break; + case o_env_override: + o = variable_buffer_output (o, "environment override", 20); + break; + case o_command: + o = variable_buffer_output (o, "command line", 12); + break; + case o_override: + o = variable_buffer_output (o, "override", 8); + break; + case o_automatic: + o = variable_buffer_output (o, "automatic", 9); + break; +#ifdef CONFIG_WITH_LOCAL_VARIABLES + case o_local: + o = variable_buffer_output (o, "local", 5); + break; +#endif + } + + return o; +} + +static char * +func_flavor (char *o, char **argv, const char *funcname UNUSED) +{ + struct variable *v = lookup_variable (argv[0], strlen (argv[0])); + + if (v == 0) + o = variable_buffer_output (o, "undefined", 9); + else + if (v->recursive) + o = variable_buffer_output (o, "recursive", 9); + else + o = variable_buffer_output (o, "simple", 6); + + return o; +} + +#ifdef CONFIG_WITH_WHERE_FUNCTION +static char * +func_where (char *o, char **argv, const char *funcname UNUSED) +{ + struct variable *v = lookup_variable (argv[0], strlen (argv[0])); + char buf[64]; + + if (v == 0) + o = variable_buffer_output (o, "undefined", 9); + else + if (v->fileinfo.filenm) + { + o = variable_buffer_output (o, v->fileinfo.filenm, strlen(v->fileinfo.filenm)); + sprintf (buf, ":%lu", v->fileinfo.lineno); + o = variable_buffer_output (o, buf, strlen(buf)); + } + else + o = variable_buffer_output (o, "no-location", 11); + + return o; +} +#endif /* CONFIG_WITH_WHERE_FUNCTION */ + +static char * +func_notdir_suffix (char *o, char **argv, const char *funcname) +{ + /* Expand the argument. */ + const char *list_iterator = argv[0]; + const char *p2; + int doneany =0; + unsigned int len=0; + + int is_suffix = funcname[0] == 's'; + int is_notdir = !is_suffix; + int stop = MAP_DIRSEP | (is_suffix ? MAP_DOT : 0); +#ifdef VMS + /* For VMS list_iterator points to a comma separated list. To use the common + [find_]next_token, create a local copy and replace the commas with + spaces. Obviously, there is a problem if there is a ',' in the VMS filename + (can only happen on ODS5), the same problem as with spaces in filenames, + which seems to be present in make on all platforms. */ + char *vms_list_iterator = alloca(strlen(list_iterator) + 1); + int i; + for (i = 0; list_iterator[i]; i++) + if (list_iterator[i] == ',') + vms_list_iterator[i] = ' '; + else + vms_list_iterator[i] = list_iterator[i]; + vms_list_iterator[i] = list_iterator[i]; + while ((p2 = find_next_token((const char**) &vms_list_iterator, &len)) != 0) +#else + while ((p2 = find_next_token (&list_iterator, &len)) != 0) +#endif + { + const char *p = p2 + len - 1; + + while (p >= p2 && ! STOP_SET (*p, stop)) + --p; + + if (p >= p2) + { + if (is_notdir) + ++p; + else if (*p != '.') + continue; + o = variable_buffer_output (o, p, len - (p - p2)); + } +#ifdef HAVE_DOS_PATHS + /* Handle the case of "d:foo/bar". */ + else if (is_notdir && p2[0] && p2[1] == ':') + { + p = p2 + 2; + o = variable_buffer_output (o, p, len - (p - p2)); + } +#endif + else if (is_notdir) + o = variable_buffer_output (o, p2, len); + + if (is_notdir || p >= p2) + { +#ifdef VMS + if (vms_comma_separator) + o = variable_buffer_output (o, ",", 1); + else +#endif + o = variable_buffer_output (o, " ", 1); + + doneany = 1; + } + } + + if (doneany) + /* Kill last space. */ + --o; + + return o; +} + + +static char * +func_basename_dir (char *o, char **argv, const char *funcname) +{ + /* Expand the argument. */ + const char *p3 = argv[0]; + const char *p2; + int doneany = 0; + unsigned int len = 0; + + int is_basename = funcname[0] == 'b'; + int is_dir = !is_basename; + int stop = MAP_DIRSEP | (is_basename ? MAP_DOT : 0) | MAP_NUL; +#ifdef VMS + /* As in func_notdir_suffix ... */ + char *vms_p3 = alloca (strlen(p3) + 1); + int i; + for (i = 0; p3[i]; i++) + if (p3[i] == ',') + vms_p3[i] = ' '; + else + vms_p3[i] = p3[i]; + vms_p3[i] = p3[i]; + while ((p2 = find_next_token((const char**) &vms_p3, &len)) != 0) +#else + while ((p2 = find_next_token (&p3, &len)) != 0) +#endif + { + const char *p = p2 + len - 1; + while (p >= p2 && ! STOP_SET (*p, stop)) + --p; + + if (p >= p2 && (is_dir)) + o = variable_buffer_output (o, p2, ++p - p2); + else if (p >= p2 && (*p == '.')) + o = variable_buffer_output (o, p2, p - p2); +#ifdef HAVE_DOS_PATHS + /* Handle the "d:foobar" case */ + else if (p2[0] && p2[1] == ':' && is_dir) + o = variable_buffer_output (o, p2, 2); +#endif + else if (is_dir) +#ifdef VMS + { + extern int vms_report_unix_paths; + if (vms_report_unix_paths) + o = variable_buffer_output (o, "./", 2); + else + o = variable_buffer_output (o, "[]", 2); + } +#else +#ifndef _AMIGA + o = variable_buffer_output (o, "./", 2); +#else + ; /* Just a nop... */ +#endif /* AMIGA */ +#endif /* !VMS */ + else + /* The entire name is the basename. */ + o = variable_buffer_output (o, p2, len); + +#ifdef VMS + if (vms_comma_separator) + o = variable_buffer_output (o, ",", 1); + else +#endif + o = variable_buffer_output (o, " ", 1); + doneany = 1; + } + + if (doneany) + /* Kill last space. */ + --o; + + return o; +} + +#if 1 /* rewrite to new MAP stuff? */ +# ifdef VMS +# define IS_PATHSEP(c) ((c) == ']') +# else +# ifdef HAVE_DOS_PATHS +# define IS_PATHSEP(c) ((c) == '/' || (c) == '\\') +# else +# define IS_PATHSEP(c) ((c) == '/') +# endif +# endif +#endif + +#ifdef CONFIG_WITH_ROOT_FUNC + +/* + $(root path) + + This is mainly for dealing with drive letters and UNC paths on Windows + and OS/2. + */ +static char * +func_root (char *o, char **argv, const char *funcname UNUSED) +{ + const char *paths = argv[0] ? argv[0] : ""; + int doneany = 0; + const char *p; + unsigned int len; + + while ((p = find_next_token (&paths, &len)) != 0) + { + const char *p2 = p; + +# ifdef HAVE_DOS_PATHS + if ( len >= 2 + && p2[1] == ':' + && ( (p2[0] >= 'A' && p2[0] <= 'Z') + || (p2[0] >= 'a' && p2[0] <= 'z'))) + { + p2 += 2; + len -= 2; + } + else if (len >= 4 && IS_PATHSEP(p2[0]) && IS_PATHSEP(p2[1]) + && !IS_PATHSEP(p2[2])) + { + /* Min recognized UNC: "//./" - find the next slash + Typical root: "//srv/shr/" */ + /* XXX: Check if //./ needs special handling. */ + + p2 += 3; + len -= 3; + while (len > 0 && !IS_PATHSEP(*p2)) + p2++, len--; + + if (len && IS_PATHSEP(p2[0]) && (len == 1 || !IS_PATHSEP(p2[1]))) + { + p2++; + len--; + + if (len) /* optional share */ + while (len > 0 && !IS_PATHSEP(*p2)) + p2++, len--; + } + else + p2 = NULL; + } + else if (IS_PATHSEP(*p2)) + { + p2++; + len--; + } + else + p2 = NULL; + +# elif defined (VMS) || defined (AMGIA) + /* XXX: VMS and AMGIA */ + O (fatal, NILF, _("$(root ) is not implemented on this platform")); +# else + if (IS_PATHSEP(*p2)) + { + p2++; + len--; + } + else + p2 = NULL; +# endif + if (p2 != NULL) + { + /* Include all subsequent path separators. */ + + while (len > 0 && IS_PATHSEP(*p2)) + p2++, len--; + o = variable_buffer_output (o, p, p2 - p); + o = variable_buffer_output (o, " ", 1); + doneany = 1; + } + } + + if (doneany) + /* Kill last space. */ + --o; + + return o; +} + +/* + $(notroot path) + + This is mainly for dealing with drive letters and UNC paths on Windows + and OS/2. + */ +static char * +func_notroot (char *o, char **argv, const char *funcname UNUSED) +{ + const char *paths = argv[0] ? argv[0] : ""; + int doneany = 0; + const char *p; + unsigned int len; + + while ((p = find_next_token (&paths, &len)) != 0) + { + const char *p2 = p; + +# ifdef HAVE_DOS_PATHS + if ( len >= 2 + && p2[1] == ':' + && ( (p2[0] >= 'A' && p2[0] <= 'Z') + || (p2[0] >= 'a' && p2[0] <= 'z'))) + { + p2 += 2; + len -= 2; + } + else if (len >= 4 && IS_PATHSEP(p2[0]) && IS_PATHSEP(p2[1]) + && !IS_PATHSEP(p2[2])) + { + /* Min recognized UNC: "//./" - find the next slash + Typical root: "//srv/shr/" */ + /* XXX: Check if //./ needs special handling. */ + unsigned int saved_len = len; + + p2 += 3; + len -= 3; + while (len > 0 && !IS_PATHSEP(*p2)) + p2++, len--; + + if (len && IS_PATHSEP(p2[0]) && (len == 1 || !IS_PATHSEP(p2[1]))) + { + p2++; + len--; + + if (len) /* optional share */ + while (len > 0 && !IS_PATHSEP(*p2)) + p2++, len--; + } + else + { + p2 = p; + len = saved_len; + } + } + +# elif defined (VMS) || defined (AMGIA) + /* XXX: VMS and AMGIA */ + O (fatal, NILF, _("$(root ) is not implemented on this platform")); +# endif + + /* Exclude all subsequent / leading path separators. */ + + while (len > 0 && IS_PATHSEP(*p2)) + p2++, len--; + if (len > 0) + o = variable_buffer_output (o, p2, len); + else + o = variable_buffer_output (o, ".", 1); + o = variable_buffer_output (o, " ", 1); + doneany = 1; + } + + if (doneany) + /* Kill last space. */ + --o; + + return o; +} + +#endif /* CONFIG_WITH_ROOT_FUNC */ + +static char * +func_addsuffix_addprefix (char *o, char **argv, const char *funcname) +{ + int fixlen = strlen (argv[0]); + const char *list_iterator = argv[1]; + int is_addprefix = funcname[3] == 'p'; + int is_addsuffix = !is_addprefix; + + int doneany = 0; + const char *p; + unsigned int len; + + while ((p = find_next_token (&list_iterator, &len)) != 0) + { + if (is_addprefix) + o = variable_buffer_output (o, argv[0], fixlen); + o = variable_buffer_output (o, p, len); + if (is_addsuffix) + o = variable_buffer_output (o, argv[0], fixlen); + o = variable_buffer_output (o, " ", 1); + doneany = 1; + } + + if (doneany) + /* Kill last space. */ + --o; + + return o; +} + +static char * +func_subst (char *o, char **argv, const char *funcname UNUSED) +{ + o = subst_expand (o, argv[2], argv[0], argv[1], strlen (argv[0]), + strlen (argv[1]), 0); + + return o; +} + +#ifdef CONFIG_WITH_DEFINED_FUNCTIONS + +/* Used by func_firstdefined and func_lastdefined to parse the optional last + argument. Returns 0 if the variable name is to be returned and 1 if it's + the variable value value. */ +static int +parse_value_name_argument (const char *arg1, const char *funcname) +{ + const char *end; + int rc; + + if (arg1 == NULL) + return 0; + + end = strchr (arg1, '\0'); + strip_whitespace (&arg1, &end); + + if (!strncmp (arg1, "name", end - arg1)) + rc = 0; + else if (!strncmp (arg1, "value", end - arg1)) + rc = 1; + else +# if 1 /* FIXME: later */ + OSS (fatal, *expanding_var, + _("second argument to `%s' function must be `name' or `value', not `%s'"), + funcname, arg1); +# else + { + /* check the expanded form */ + char *exp = expand_argument (arg1, strchr (arg1, '\0')); + arg1 = exp; + end = strchr (arg1, '\0'); + strip_whitespace (&arg1, &end); + + if (!strncmp (arg1, "name", end - arg1)) + rc = 0; + else if (!strncmp (arg1, "value", end - arg1)) + rc = 1; + else + OSS (fatal, *expanding_var, + _("second argument to `%s' function must be `name' or `value', not `%s'"), + funcname, exp); + free (exp); + } +# endif + + return rc; +} + +/* Given a list of variable names (ARGV[0]), returned the first variable which + is defined (i.e. value is not empty). ARGV[1] indicates whether to return + the variable name or its value. */ +static char * +func_firstdefined (char *o, char **argv, const char *funcname) +{ + unsigned int i; + const char *words = argv[0]; /* Use a temp variable for find_next_token */ + const char *p; + int ret_value = parse_value_name_argument (argv[1], funcname); + + /* FIXME: Optimize by not expanding the arguments, but instead expand them + one by one here. This will require a find_next_token variant which + takes `$(' and `)' into account. */ + while ((p = find_next_token (&words, &i)) != NULL) + { + struct variable *v = lookup_variable (p, i); + if (v && v->value_length) + { + if (ret_value) + variable_expand_string_2 (o, v->value, v->value_length, &o); + else + o = variable_buffer_output (o, p, i); + break; + } + } + + return o; +} + +/* Given a list of variable names (ARGV[0]), returned the last variable which + is defined (i.e. value is not empty). ARGV[1] indicates whether to return + the variable name or its value. */ +static char * +func_lastdefined (char *o, char **argv, const char *funcname) +{ + struct variable *last_v = NULL; + unsigned int i; + const char *words = argv[0]; /* Use a temp variable for find_next_token */ + const char *p; + int ret_value = parse_value_name_argument (argv[1], funcname); + + /* FIXME: Optimize this. Walk from the end on unexpanded arguments. */ + while ((p = find_next_token (&words, &i)) != NULL) + { + struct variable *v = lookup_variable (p, i); + if (v && v->value_length) + { + last_v = v; + break; + } + } + + if (last_v != NULL) + { + if (ret_value) + variable_expand_string_2 (o, last_v->value, last_v->value_length, &o); + else + o = variable_buffer_output (o, last_v->name, last_v->length); + } + return o; +} + +#endif /* CONFIG_WITH_DEFINED_FUNCTIONS */ + +static char * +func_firstword (char *o, char **argv, const char *funcname UNUSED) +{ + unsigned int i; + const char *words = argv[0]; /* Use a temp variable for find_next_token */ + const char *p = find_next_token (&words, &i); + + if (p != 0) + o = variable_buffer_output (o, p, i); + + return o; +} + +static char * +func_lastword (char *o, char **argv, const char *funcname UNUSED) +{ + unsigned int i; + const char *words = argv[0]; /* Use a temp variable for find_next_token */ + const char *p = NULL; + const char *t; + + while ((t = find_next_token (&words, &i))) + p = t; + + if (p != 0) + o = variable_buffer_output (o, p, i); + + return o; +} + +static char * +func_words (char *o, char **argv, const char *funcname UNUSED) +{ + int i = 0; + const char *word_iterator = argv[0]; + char buf[20]; + + while (find_next_token (&word_iterator, NULL) != 0) + ++i; + + sprintf (buf, "%d", i); + o = variable_buffer_output (o, buf, strlen (buf)); + + return o; +} + +/* Set begpp to point to the first non-whitespace character of the string, + * and endpp to point to the last non-whitespace character of the string. + * If the string is empty or contains nothing but whitespace, endpp will be + * begpp-1. + */ +char * +strip_whitespace (const char **begpp, const char **endpp) +{ + while (*begpp <= *endpp && ISSPACE (**begpp)) + (*begpp) ++; + while (*endpp >= *begpp && ISSPACE (**endpp)) + (*endpp) --; + return (char *)*begpp; +} + +static void +check_numeric (const char *s, const char *msg) +{ + const char *end = s + strlen (s) - 1; + const char *beg = s; + strip_whitespace (&s, &end); + + for (; s <= end; ++s) + if (!ISDIGIT (*s)) /* ISDIGIT only evals its arg once: see makeint.h. */ + break; + + if (s <= end || end - beg < 0) + OSS (fatal, *expanding_var, "%s: '%s'", msg, beg); +} + + + +static char * +func_word (char *o, char **argv, const char *funcname UNUSED) +{ + const char *end_p; + const char *p; + int i; + + /* Check the first argument. */ + check_numeric (argv[0], _("non-numeric first argument to 'word' function")); + i = atoi (argv[0]); + + if (i == 0) + O (fatal, *expanding_var, + _("first argument to 'word' function must be greater than 0")); + + end_p = argv[1]; + while ((p = find_next_token (&end_p, 0)) != 0) + if (--i == 0) + break; + + if (i == 0) + o = variable_buffer_output (o, p, end_p - p); + + return o; +} + +static char * +func_wordlist (char *o, char **argv, const char *funcname UNUSED) +{ + int start, count; + + /* Check the arguments. */ + check_numeric (argv[0], + _("non-numeric first argument to 'wordlist' function")); + check_numeric (argv[1], + _("non-numeric second argument to 'wordlist' function")); + + start = atoi (argv[0]); + if (start < 1) + ON (fatal, *expanding_var, + "invalid first argument to 'wordlist' function: '%d'", start); + + count = atoi (argv[1]) - start + 1; + + if (count > 0) + { + const char *p; + const char *end_p = argv[2]; + + /* Find the beginning of the "start"th word. */ + while (((p = find_next_token (&end_p, 0)) != 0) && --start) + ; + + if (p) + { + /* Find the end of the "count"th word from start. */ + while (--count && (find_next_token (&end_p, 0) != 0)) + ; + + /* Return the stuff in the middle. */ + o = variable_buffer_output (o, p, end_p - p); + } + } + + return o; +} + +static char * +func_findstring (char *o, char **argv, const char *funcname UNUSED) +{ + /* Find the first occurrence of the first string in the second. */ + if (strstr (argv[1], argv[0]) != 0) + o = variable_buffer_output (o, argv[0], strlen (argv[0])); + + return o; +} + +static char * +func_foreach (char *o, char **argv, const char *funcname UNUSED) +{ + /* expand only the first two. */ + char *varname = expand_argument (argv[0], NULL); + char *list = expand_argument (argv[1], NULL); + const char *body = argv[2]; +#ifdef CONFIG_WITH_VALUE_LENGTH + long body_len = strlen (body); +#endif + + int doneany = 0; + const char *list_iterator = list; + const char *p; + unsigned int len; + struct variable *var; + + /* Clean up the variable name by removing whitespace. */ + char *vp = next_token (varname); + end_of_token (vp)[0] = '\0'; + + push_new_variable_scope (); + var = define_variable (vp, strlen (vp), "", o_automatic, 0); + + /* loop through LIST, put the value in VAR and expand BODY */ + while ((p = find_next_token (&list_iterator, &len)) != 0) + { +#ifndef CONFIG_WITH_VALUE_LENGTH + char *result = 0; + + free (var->value); + var->value = xstrndup (p, len); + + result = allocated_variable_expand (body); + + o = variable_buffer_output (o, result, strlen (result)); + o = variable_buffer_output (o, " ", 1); + doneany = 1; + free (result); +#else /* CONFIG_WITH_VALUE_LENGTH */ + if (len >= var->value_alloc_len) + { +# ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE + if (var->rdonly_val) + var->rdonly_val = 0; + else +# endif + free (var->value); + var->value_alloc_len = VAR_ALIGN_VALUE_ALLOC (len + 1); + var->value = xmalloc (var->value_alloc_len); + } + memcpy (var->value, p, len); + var->value[len] = '\0'; + var->value_length = len; + VARIABLE_CHANGED (var); + + variable_expand_string_2 (o, body, body_len, &o); + o = variable_buffer_output (o, " ", 1); + doneany = 1; +#endif /* CONFIG_WITH_VALUE_LENGTH */ + } + + if (doneany) + /* Kill the last space. */ + --o; + + pop_variable_scope (); + free (varname); + free (list); + + return o; +} + +#ifdef CONFIG_WITH_LOOP_FUNCTIONS + +/* Helper for func_for that evaluates the INIT and NEXT parts. */ +static void +helper_eval (char *text, size_t text_len) +{ + unsigned int buf_len; + char *buf; + + install_variable_buffer (&buf, &buf_len); + eval_buffer (text, NULL, text + text_len); + restore_variable_buffer (buf, buf_len); +} + +/* + $(for init,condition,next,body) + */ +static char * +func_for (char *o, char **argv, const char *funcname UNUSED) +{ + char *init = argv[0]; + const char *cond = argv[1]; + const char *next = argv[2]; + size_t next_len = strlen (next); + char *next_buf = xmalloc (next_len + 1); + const char *body = argv[3]; + size_t body_len = strlen (body); + unsigned int doneany = 0; + + push_new_variable_scope (); + + /* Evaluate INIT. */ + + helper_eval (init, strlen (init)); + + /* Loop till COND is false. */ + + while (expr_eval_if_conditionals (cond, NULL) == 0 /* true */) + { + /* Expand BODY. */ + + if (!doneany) + doneany = 1; + else + o = variable_buffer_output (o, " ", 1); + variable_expand_string_2 (o, body, body_len, &o); + + /* Evaluate NEXT. */ + + memcpy (next_buf, next, next_len + 1); + helper_eval (next_buf, next_len); + } + + pop_variable_scope (); + free (next_buf); + + return o; +} + +/* + $(while condition,body) + */ +static char * +func_while (char *o, char **argv, const char *funcname UNUSED) +{ + const char *cond = argv[0]; + const char *body = argv[1]; + size_t body_len = strlen (body); + unsigned int doneany = 0; + + push_new_variable_scope (); + + while (expr_eval_if_conditionals (cond, NULL) == 0 /* true */) + { + if (!doneany) + doneany = 1; + else + o = variable_buffer_output (o, " ", 1); + variable_expand_string_2 (o, body, body_len, &o); + } + + pop_variable_scope (); + + return o; +} + +#endif /* CONFIG_WITH_LOOP_FUNCTIONS */ + +struct a_word +{ + struct a_word *next; + struct a_word *chain; + char *str; + int length; + int matched; +}; + +static unsigned long +a_word_hash_1 (const void *key) +{ + return_STRING_HASH_1 (((struct a_word const *) key)->str); +} + +static unsigned long +a_word_hash_2 (const void *key) +{ + return_STRING_HASH_2 (((struct a_word const *) key)->str); +} + +static int +a_word_hash_cmp (const void *x, const void *y) +{ + int result = ((struct a_word const *) x)->length - ((struct a_word const *) y)->length; + if (result) + return result; + return_STRING_COMPARE (((struct a_word const *) x)->str, + ((struct a_word const *) y)->str); +} + +struct a_pattern +{ + struct a_pattern *next; + char *str; + char *percent; + int length; +#ifdef KMK + unsigned int sfxlen; +#endif +}; + +static char * +func_filter_filterout (char *o, char **argv, const char *funcname) +{ + struct a_word *wordhead; + struct a_word **wordtail; + struct a_word *wp; + struct a_pattern *pathead; + struct a_pattern **pattail; + struct a_pattern *pp; + + struct hash_table a_word_table; + int is_filter = funcname[CSTRLEN ("filter")] == '\0'; + const char *pat_iterator = argv[0]; + const char *word_iterator = argv[1]; + int literals = 0; + int words = 0; + int hashing = 0; + char *p; + unsigned int len; + + /* Chop ARGV[0] up into patterns to match against the words. + We don't need to preserve it because our caller frees all the + argument memory anyway. */ + + pattail = &pathead; + while ((p = find_next_token (&pat_iterator, &len)) != 0) + { + struct a_pattern *pat = alloca (sizeof (struct a_pattern)); + + *pattail = pat; + pattail = &pat->next; + + if (*pat_iterator != '\0') + ++pat_iterator; + + pat->str = p; + p[len] = '\0'; + pat->percent = find_percent (p); + if (pat->percent == 0) + literals++; +#ifdef KMK + pat->sfxlen = pat->percent ? strlen(pat->percent + 1) : 0; +#endif + + /* find_percent() might shorten the string so LEN is wrong. */ + pat->length = strlen (pat->str); + } + *pattail = 0; + + /* Chop ARGV[1] up into words to match against the patterns. */ + + wordtail = &wordhead; + while ((p = find_next_token (&word_iterator, &len)) != 0) + { + struct a_word *word = alloca (sizeof (struct a_word)); + + *wordtail = word; + wordtail = &word->next; + + if (*word_iterator != '\0') + ++word_iterator; + + p[len] = '\0'; + word->str = p; + word->length = len; + word->matched = 0; + word->chain = 0; + words++; + } + *wordtail = 0; + + /* Only use a hash table if arg list lengths justifies the cost. */ + hashing = (literals >= 2 && (literals * words) >= 10); + if (hashing) + { + hash_init (&a_word_table, words, a_word_hash_1, a_word_hash_2, + a_word_hash_cmp); + for (wp = wordhead; wp != 0; wp = wp->next) + { + struct a_word *owp = hash_insert (&a_word_table, wp); + if (owp) + wp->chain = owp; + } + } + + if (words) + { + int doneany = 0; + + /* Run each pattern through the words, killing words. */ + for (pp = pathead; pp != 0; pp = pp->next) + { + if (pp->percent) + for (wp = wordhead; wp != 0; wp = wp->next) +#ifdef KMK + wp->matched |= pattern_matches_ex (pp->str, pp->percent, pp->sfxlen, + wp->str, wp->length); +#else + wp->matched |= pattern_matches (pp->str, pp->percent, wp->str); +#endif + else if (hashing) + { + struct a_word a_word_key; + a_word_key.str = pp->str; + a_word_key.length = pp->length; + wp = hash_find_item (&a_word_table, &a_word_key); + while (wp) + { + wp->matched |= 1; + wp = wp->chain; + } + } + else + for (wp = wordhead; wp != 0; wp = wp->next) + wp->matched |= (wp->length == pp->length + && strneq (pp->str, wp->str, wp->length)); + } + + /* Output the words that matched (or didn't, for filter-out). */ + for (wp = wordhead; wp != 0; wp = wp->next) + if (is_filter ? wp->matched : !wp->matched) + { + o = variable_buffer_output (o, wp->str, strlen (wp->str)); + o = variable_buffer_output (o, " ", 1); + doneany = 1; + } + + if (doneany) + /* Kill the last space. */ + --o; + } + + if (hashing) + hash_free (&a_word_table, 0); + + return o; +} + + +static char * +func_strip (char *o, char **argv, const char *funcname UNUSED) +{ + const char *p = argv[0]; + int doneany = 0; + + while (*p != '\0') + { + int i=0; + const char *word_start; + + NEXT_TOKEN (p); + word_start = p; + for (i=0; *p != '\0' && !ISSPACE (*p); ++p, ++i) + {} + if (!i) + break; + o = variable_buffer_output (o, word_start, i); + o = variable_buffer_output (o, " ", 1); + doneany = 1; + } + + if (doneany) + /* Kill the last space. */ + --o; + + return o; +} + +/* + Print a warning or fatal message. +*/ +static char * +func_error (char *o, char **argv, const char *funcname) +{ + char **argvp; + char *msg, *p; + int len; + + /* The arguments will be broken on commas. Rather than create yet + another special case where function arguments aren't broken up, + just create a format string that puts them back together. */ + for (len=0, argvp=argv; *argvp != 0; ++argvp) + len += strlen (*argvp) + 2; + + p = msg = alloca (len + 1); + + for (argvp=argv; argvp[1] != 0; ++argvp) + { + strcpy (p, *argvp); + p += strlen (*argvp); + *(p++) = ','; + *(p++) = ' '; + } + strcpy (p, *argvp); + + switch (*funcname) + { + case 'e': + OS (fatal, reading_file, "%s", msg); + + case 'w': + OS (error, reading_file, "%s", msg); + break; + + case 'i': + outputs (0, msg); + outputs (0, "\n"); + break; + + default: + OS (fatal, *expanding_var, "Internal error: func_error: '%s'", funcname); + } + + /* The warning function expands to the empty string. */ + return o; +} + +#ifdef KMK +/* Compare strings *S1 and *S2. + Return negative if the first is less, positive if it is greater, + zero if they are equal. */ + +static int +version_compare_wrapper (const void *v1, const void *v2) +{ + const char *s1 = *((char **)v1); + const char *s2 = *((char **)v2); + return version_compare (s1, s2); +} +#endif /* KMK */ + +/* + chop argv[0] into words, and sort them. + */ +static char * +func_sort (char *o, char **argv, const char *funcname UNUSED) +{ + const char *t; + char **words; + int wordi; + char *p; + unsigned int len; + + /* Find the maximum number of words we'll have. */ + t = argv[0]; + wordi = 0; + while ((p = find_next_token (&t, NULL)) != 0) + { + ++t; + ++wordi; + } + + words = xmalloc ((wordi == 0 ? 1 : wordi) * sizeof (char *)); + + /* Now assign pointers to each string in the array. */ + t = argv[0]; + wordi = 0; + while ((p = find_next_token (&t, &len)) != 0) + { + if (*t != '\0') /* bird: Fixes access beyond end of string and overflowing words array. */ + ++t; + p[len] = '\0'; + words[wordi++] = p; + } + + if (wordi) + { + int i; + + /* Now sort the list of words. */ +#ifdef KMK + if (funcname[0] == 'v' || funcname[1] == 'v') + qsort (words, wordi, sizeof (char *), version_compare_wrapper); + else + qsort (words, wordi, sizeof (char *), alpha_compare); +#else + qsort (words, wordi, sizeof (char *), alpha_compare); +#endif + + /* Now write the sorted list, uniquified. */ +#ifdef CONFIG_WITH_RSORT + if (*funcname != 'r') + { + /* sort */ +#endif + for (i = 0; i < wordi; ++i) + { + len = strlen (words[i]); + if (i == wordi - 1 || strlen (words[i + 1]) != len + || strcmp (words[i], words[i + 1])) + { + o = variable_buffer_output (o, words[i], len); + o = variable_buffer_output (o, " ", 1); + } + } +#ifdef CONFIG_WITH_RSORT + } + else + { + /* rsort - reverse the result */ + i = wordi; + while (i-- > 0) + { + len = strlen (words[i]); + if (i == 0 || strlen (words[i - 1]) != len + || strcmp (words[i], words[i - 1])) + { + o = variable_buffer_output (o, words[i], len); + o = variable_buffer_output (o, " ", 1); + } + } + } +#endif + + /* Kill the last space. */ + --o; + } + + free (words); + + return o; +} + +/* + $(if condition,true-part[,false-part]) + + CONDITION is false iff it evaluates to an empty string. White + space before and after condition are stripped before evaluation. + + If CONDITION is true, then TRUE-PART is evaluated, otherwise FALSE-PART is + evaluated (if it exists). Because only one of the two PARTs is evaluated, + you can use $(if ...) to create side-effects (with $(shell ...), for + example). +*/ + +static char * +func_if (char *o, char **argv, const char *funcname UNUSED) +{ + const char *begp = argv[0]; + const char *endp = begp + strlen (argv[0]) - 1; + int result = 0; + + /* Find the result of the condition: if we have a value, and it's not + empty, the condition is true. If we don't have a value, or it's the + empty string, then it's false. */ + + strip_whitespace (&begp, &endp); + + if (begp <= endp) + { + char *expansion = expand_argument (begp, endp+1); + + result = strlen (expansion); + free (expansion); + } + + /* If the result is true (1) we want to eval the first argument, and if + it's false (0) we want to eval the second. If the argument doesn't + exist we do nothing, otherwise expand it and add to the buffer. */ + + argv += 1 + !result; + + if (*argv) + { + char *expansion = expand_argument (*argv, NULL); + + o = variable_buffer_output (o, expansion, strlen (expansion)); + + free (expansion); + } + + return o; +} + +/* + $(or condition1[,condition2[,condition3[...]]]) + + A CONDITION is false iff it evaluates to an empty string. White + space before and after CONDITION are stripped before evaluation. + + CONDITION1 is evaluated. If it's true, then this is the result of + expansion. If it's false, CONDITION2 is evaluated, and so on. If none of + the conditions are true, the expansion is the empty string. + + Once a CONDITION is true no further conditions are evaluated + (short-circuiting). +*/ + +static char * +func_or (char *o, char **argv, const char *funcname UNUSED) +{ + for ( ; *argv ; ++argv) + { + const char *begp = *argv; + const char *endp = begp + strlen (*argv) - 1; + char *expansion; + int result = 0; + + /* Find the result of the condition: if it's false keep going. */ + + strip_whitespace (&begp, &endp); + + if (begp > endp) + continue; + + expansion = expand_argument (begp, endp+1); + result = strlen (expansion); + + /* If the result is false keep going. */ + if (!result) + { + free (expansion); + continue; + } + + /* It's true! Keep this result and return. */ + o = variable_buffer_output (o, expansion, result); + free (expansion); + break; + } + + return o; +} + +/* + $(and condition1[,condition2[,condition3[...]]]) + + A CONDITION is false iff it evaluates to an empty string. White + space before and after CONDITION are stripped before evaluation. + + CONDITION1 is evaluated. If it's false, then this is the result of + expansion. If it's true, CONDITION2 is evaluated, and so on. If all of + the conditions are true, the expansion is the result of the last condition. + + Once a CONDITION is false no further conditions are evaluated + (short-circuiting). +*/ + +static char * +func_and (char *o, char **argv, const char *funcname UNUSED) +{ + char *expansion; + + while (1) + { + const char *begp = *argv; + const char *endp = begp + strlen (*argv) - 1; + int result; + + /* An empty condition is always false. */ + strip_whitespace (&begp, &endp); + if (begp > endp) + return o; + + expansion = expand_argument (begp, endp+1); + result = strlen (expansion); + + /* If the result is false, stop here: we're done. */ + if (!result) + break; + + /* Otherwise the result is true. If this is the last one, keep this + result and quit. Otherwise go on to the next one! */ + + if (*(++argv)) + free (expansion); + else + { + o = variable_buffer_output (o, expansion, result); + break; + } + } + + free (expansion); + + return o; +} + +static char * +func_wildcard (char *o, char **argv, const char *funcname UNUSED) +{ +#ifdef _AMIGA + o = wildcard_expansion (argv[0], o); +#else + char *p = string_glob (argv[0]); + o = variable_buffer_output (o, p, strlen (p)); +#endif + return o; +} + +/* + $(eval ) + + Always resolves to the empty string. + + Treat the arguments as a segment of makefile, and parse them. +*/ + +static char * +func_eval (char *o, char **argv, const char *funcname UNUSED) +{ + char *buf; + unsigned int len; + + /* Eval the buffer. Pop the current variable buffer setting so that the + eval'd code can use its own without conflicting. */ + + install_variable_buffer (&buf, &len); + +#ifndef CONFIG_WITH_VALUE_LENGTH + eval_buffer (argv[0], NULL); +#else + eval_buffer (argv[0], NULL, strchr (argv[0], '\0')); +#endif + + restore_variable_buffer (buf, len); + + return o; +} + + +#ifdef CONFIG_WITH_EVALPLUS +/* Same as func_eval except that we push and pop the local variable + context before evaluating the buffer. */ +static char * +func_evalctx (char *o, char **argv, const char *funcname UNUSED) +{ + char *buf; + unsigned int len; + + /* Eval the buffer. Pop the current variable buffer setting so that the + eval'd code can use its own without conflicting. */ + + install_variable_buffer (&buf, &len); + + push_new_variable_scope (); + + eval_buffer (argv[0], NULL, strchr (argv[0], '\0')); + + pop_variable_scope (); + + restore_variable_buffer (buf, len); + + return o; +} + +/* A mix of func_eval and func_value, saves memory for the expansion. + This implements both evalval and evalvalctx, the latter has its own + variable context just like evalctx. */ +static char * +func_evalval (char *o, char **argv, const char *funcname) +{ + /* Look up the variable. */ + struct variable *v = lookup_variable (argv[0], strlen (argv[0])); + if (v) + { + char *buf; + unsigned int len; + int var_ctx; + size_t off; + const floc *reading_file_saved = reading_file; +# ifdef CONFIG_WITH_MAKE_STATS + unsigned long long uStartTick = CURRENT_CLOCK_TICK(); +# ifndef CONFIG_WITH_COMPILER + MAKE_STATS_2(v->evalval_count++); +# endif +# endif + + var_ctx = !strcmp (funcname, "evalvalctx"); + if (var_ctx) + push_new_variable_scope (); + if (v->fileinfo.filenm) + reading_file = &v->fileinfo; + +# ifdef CONFIG_WITH_COMPILER + /* If this variable has been evaluated more than a few times, it make + sense to compile it to speed up the processing. */ + + v->evalval_count++; + if ( v->evalprog + || (v->evalval_count == 3 && kmk_cc_compile_variable_for_eval (v))) + { + install_variable_buffer (&buf, &len); /* Really necessary? */ + kmk_exec_eval_variable (v); + restore_variable_buffer (buf, len); + } + else +# endif + { + /* Make a copy of the value to the variable buffer first since + eval_buffer will make changes to its input. */ + + off = o - variable_buffer; + variable_buffer_output (o, v->value, v->value_length + 1); + o = variable_buffer + off; + assert (!o[v->value_length]); + + install_variable_buffer (&buf, &len); /* Really necessary? */ + eval_buffer (o, NULL, o + v->value_length); + restore_variable_buffer (buf, len); + } + + reading_file = reading_file_saved; + if (var_ctx) + pop_variable_scope (); + + MAKE_STATS_2(v->cTicksEvalVal += CURRENT_CLOCK_TICK() - uStartTick); + } + + return o; +} + +/* Optimizes the content of one or more variables to save time in + the eval functions. This function will collapse line continuations + and remove comments. */ +static char * +func_eval_optimize_variable (char *o, char **argv, const char *funcname) +{ + unsigned int i; + + for (i = 0; argv[i]; i++) + { + struct variable *v = lookup_variable (argv[i], strlen (argv[i])); +# ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE + if (v && v->origin != o_automatic && !v->rdonly_val) +# else + if (v && v->origin != o_automatic) +# endif + { + char *eos, *src; + + eos = collapse_continuations (v->value, v->value_length); + v->value_length = eos - v->value; + + /* remove comments */ + + src = memchr (v->value, '#', v->value_length); + if (src) + { + unsigned char ch = '\0'; + char *dst = src; + do + { + /* drop blanks preceeding the comment */ + while (dst > v->value) + { + ch = (unsigned char)dst[-1]; + if (!ISBLANK (ch)) + break; + dst--; + } + + /* advance SRC to eol / eos. */ + src = memchr (src, '\n', eos - src); + if (!src) + break; + + /* drop a preceeding newline if possible (full line comment) */ + if (dst > v->value && dst[-1] == '\n') + dst--; + + /* copy till next comment or eol. */ + while (src < eos) + { + ch = *src++; + if (ch == '#') + break; + *dst++ = ch; + } + } + while (ch == '#' && src < eos); + + *dst = '\0'; + v->value_length = dst - v->value; + } + + VARIABLE_CHANGED (v); + +# ifdef CONFIG_WITH_COMPILER + /* Compile the variable for evalval, evalctx and expansion. */ + + if ( v->recursive + && !IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR (v)) + kmk_cc_compile_variable_for_expand (v); + kmk_cc_compile_variable_for_eval (v); +# endif + } + else if (v) + OSS (error, NILF, _("$(%s ): variable `%s' is of the wrong type\n"), funcname, v->name); + } + + return o; +} + +#endif /* CONFIG_WITH_EVALPLUS */ + +static char * +func_value (char *o, char **argv, const char *funcname UNUSED) +{ + /* Look up the variable. */ + struct variable *v = lookup_variable (argv[0], strlen (argv[0])); + + /* Copy its value into the output buffer without expanding it. */ + if (v) +#ifdef CONFIG_WITH_VALUE_LENGTH + { + assert (v->value_length == strlen (v->value)); + o = variable_buffer_output (o, v->value, v->value_length); + } +#else + o = variable_buffer_output (o, v->value, strlen (v->value)); +#endif + + return o; +} + +/* + \r is replaced on UNIX as well. Is this desirable? + */ +static void +fold_newlines (char *buffer, unsigned int *length, int trim_newlines) +{ + char *dst = buffer; + char *src = buffer; + char *last_nonnl = buffer - 1; + src[*length] = 0; + for (; *src != '\0'; ++src) + { + if (src[0] == '\r' && src[1] == '\n') + continue; + if (*src == '\n') + { + *dst++ = ' '; + } + else + { + last_nonnl = dst; + *dst++ = *src; + } + } + + if (!trim_newlines && (last_nonnl < (dst - 2))) + last_nonnl = dst - 2; + + *(++last_nonnl) = '\0'; + *length = last_nonnl - buffer; +} + +pid_t shell_function_pid = 0; +static int shell_function_completed; + +void +shell_completed (int exit_code, int exit_sig) +{ + char buf[256]; + + shell_function_pid = 0; + if (exit_sig == 0 && exit_code == 127) + shell_function_completed = -1; + else + shell_function_completed = 1; + + sprintf (buf, "%d", exit_code); + define_variable_cname (".SHELLSTATUS", buf, o_override, 0); +} + +#ifdef WINDOWS32 +/*untested*/ + +# ifndef CONFIG_NEW_WIN_CHILDREN +#include +#include +#include "sub_proc.h" + +int +windows32_openpipe (int *pipedes, int errfd, pid_t *pid_p, char **command_argv, char **envp) +{ + SECURITY_ATTRIBUTES saAttr; + HANDLE hIn = INVALID_HANDLE_VALUE; + HANDLE hErr = INVALID_HANDLE_VALUE; + HANDLE hChildOutRd; + HANDLE hChildOutWr; + HANDLE hProcess, tmpIn, tmpErr; + DWORD e; + + /* Set status for return. */ + pipedes[0] = pipedes[1] = -1; + *pid_p = (pid_t)-1; + + saAttr.nLength = sizeof (SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + /* Standard handles returned by GetStdHandle can be NULL or + INVALID_HANDLE_VALUE if the parent process closed them. If that + happens, we open the null device and pass its handle to + process_begin below as the corresponding handle to inherit. */ + tmpIn = GetStdHandle (STD_INPUT_HANDLE); + if (DuplicateHandle (GetCurrentProcess (), tmpIn, + GetCurrentProcess (), &hIn, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) + { + e = GetLastError (); + if (e == ERROR_INVALID_HANDLE) + { + tmpIn = CreateFile ("NUL", GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (tmpIn != INVALID_HANDLE_VALUE + && DuplicateHandle (GetCurrentProcess (), tmpIn, + GetCurrentProcess (), &hIn, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) + CloseHandle (tmpIn); + } + if (hIn == INVALID_HANDLE_VALUE) + { + ON (error, NILF, + _("windows32_openpipe: DuplicateHandle(In) failed (e=%ld)\n"), e); + return -1; + } + } + tmpErr = (HANDLE)_get_osfhandle (errfd); + if (DuplicateHandle (GetCurrentProcess (), tmpErr, + GetCurrentProcess (), &hErr, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) + { + e = GetLastError (); + if (e == ERROR_INVALID_HANDLE) + { + tmpErr = CreateFile ("NUL", GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (tmpErr != INVALID_HANDLE_VALUE + && DuplicateHandle (GetCurrentProcess (), tmpErr, + GetCurrentProcess (), &hErr, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) + CloseHandle (tmpErr); + } + if (hErr == INVALID_HANDLE_VALUE) + { + ON (error, NILF, + _("windows32_openpipe: DuplicateHandle(Err) failed (e=%ld)\n"), e); + return -1; + } + } + + if (! CreatePipe (&hChildOutRd, &hChildOutWr, &saAttr, 0)) + { + ON (error, NILF, _("CreatePipe() failed (e=%ld)\n"), GetLastError()); + return -1; + } + + hProcess = process_init_fd (hIn, hChildOutWr, hErr); + + if (!hProcess) + { + O (error, NILF, _("windows32_openpipe(): process_init_fd() failed\n")); + return -1; + } + + /* make sure that CreateProcess() has Path it needs */ + sync_Path_environment (); + /* 'sync_Path_environment' may realloc 'environ', so take note of + the new value. */ + envp = environ; + + if (! process_begin (hProcess, command_argv, envp, command_argv[0], NULL)) + { + /* register process for wait */ + process_register (hProcess); + + /* set the pid for returning to caller */ + *pid_p = (pid_t) hProcess; + + /* set up to read data from child */ + pipedes[0] = _open_osfhandle ((intptr_t) hChildOutRd, O_RDONLY); + + /* this will be closed almost right away */ + pipedes[1] = _open_osfhandle ((intptr_t) hChildOutWr, O_APPEND); + return 0; + } + else + { + /* reap/cleanup the failed process */ + process_cleanup (hProcess); + + /* close handles which were duplicated, they weren't used */ + if (hIn != INVALID_HANDLE_VALUE) + CloseHandle (hIn); + if (hErr != INVALID_HANDLE_VALUE) + CloseHandle (hErr); + + /* close pipe handles, they won't be used */ + CloseHandle (hChildOutRd); + CloseHandle (hChildOutWr); + + return -1; + } +} +# endif /* !CONFIG_NEW_WIN_CHILDREN */ +#endif + + +#ifdef __MSDOS__ +FILE * +msdos_openpipe (int* pipedes, int *pidp, char *text) +{ + FILE *fpipe=0; + /* MSDOS can't fork, but it has 'popen'. */ + struct variable *sh = lookup_variable ("SHELL", 5); + int e; + extern int dos_command_running, dos_status; + + /* Make sure not to bother processing an empty line. */ + NEXT_TOKEN (text); + if (*text == '\0') + return 0; + + if (sh) + { + char buf[PATH_MAX + 7]; + /* This makes sure $SHELL value is used by $(shell), even + though the target environment is not passed to it. */ + sprintf (buf, "SHELL=%s", sh->value); + putenv (buf); + } + + e = errno; + errno = 0; + dos_command_running = 1; + dos_status = 0; + /* If dos_status becomes non-zero, it means the child process + was interrupted by a signal, like SIGINT or SIGQUIT. See + fatal_error_signal in commands.c. */ + fpipe = popen (text, "rt"); + dos_command_running = 0; + if (!fpipe || dos_status) + { + pipedes[0] = -1; + *pidp = -1; + if (dos_status) + errno = EINTR; + else if (errno == 0) + errno = ENOMEM; + if (fpipe) + pclose (fpipe); + shell_completed (127, 0); + } + else + { + pipedes[0] = fileno (fpipe); + *pidp = 42; /* Yes, the Meaning of Life, the Universe, and Everything! */ + errno = e; + } + return fpipe; +} +#endif + +/* + Do shell spawning, with the naughty bits for different OSes. + */ + +#ifdef VMS + +/* VMS can't do $(shell ...) */ + +char * +func_shell_base (char *o, char **argv, int trim_newlines) +{ + fprintf (stderr, "This platform does not support shell\n"); + die (MAKE_TROUBLE); + return NULL; +} + +#define func_shell 0 + +#else +#ifndef _AMIGA +char * +func_shell_base (char *o, char **argv, int trim_newlines) +{ + char *batch_filename = NULL; + int errfd; +#ifdef __MSDOS__ + FILE *fpipe; +#endif + char **command_argv; + const char * volatile error_prefix; /* bird: this volatile ~~and the 'o' one~~, is for shutting up gcc warnings */ + char **envp; + int pipedes[2]; + pid_t pid; + +#ifndef __MSDOS__ +#ifdef WINDOWS32 + /* Reset just_print_flag. This is needed on Windows when batch files + are used to run the commands, because we normally refrain from + creating batch files under -n. */ + int j_p_f = just_print_flag; + just_print_flag = 0; +#endif + + /* Construct the argument list. */ + command_argv = construct_command_argv (argv[0], NULL, NULL, 0, + &batch_filename); + if (command_argv == 0) + { +#ifdef WINDOWS32 + just_print_flag = j_p_f; +#endif + return o; + } +#endif /* !__MSDOS__ */ + + /* Using a target environment for 'shell' loses in cases like: + export var = $(shell echo foobie) + bad := $(var) + because target_environment hits a loop trying to expand $(var) to put it + in the environment. This is even more confusing when 'var' was not + explicitly exported, but just appeared in the calling environment. + + See Savannah bug #10593. + + envp = target_environment (NULL); + */ + + envp = environ; + + /* For error messages. */ + if (reading_file && reading_file->filenm) + { + char *p = alloca (strlen (reading_file->filenm)+11+4); + sprintf (p, "%s:%lu: ", reading_file->filenm, + reading_file->lineno + reading_file->offset); + error_prefix = p; + } + else + error_prefix = ""; + + /* Set up the output in case the shell writes something. */ + output_start (); + +#ifdef CONFIG_WITH_OUTPUT_IN_MEMORY + errfd = -1; /** @todo fixme */ +#else + errfd = (output_context && output_context->err >= 0 + ? output_context->err : FD_STDERR); +#endif + +#if defined(__MSDOS__) + fpipe = msdos_openpipe (pipedes, &pid, argv[0]); + if (pipedes[0] < 0) + { + perror_with_name (error_prefix, "pipe"); + return o; + } + +#elif defined(WINDOWS32) +# ifdef CONFIG_NEW_WIN_CHILDREN + pipedes[1] = -1; + MkWinChildCreateWithStdOutPipe (command_argv, envp, errfd, &pid, &pipedes[0]); +# else + windows32_openpipe (pipedes, errfd, &pid, command_argv, envp); +# endif + /* Restore the value of just_print_flag. */ + just_print_flag = j_p_f; + + if (pipedes[0] < 0) + { + /* Open of the pipe failed, mark as failed execution. */ + shell_completed (127, 0); + perror_with_name (error_prefix, "pipe"); + return o; + } + +#else + if (pipe (pipedes) < 0) + { + perror_with_name (error_prefix, "pipe"); + return o; + } + + /* Close handles that are unnecessary for the child process. */ + CLOSE_ON_EXEC(pipedes[1]); + CLOSE_ON_EXEC(pipedes[0]); + + { + struct output out; + out.syncout = 1; + out.out = pipedes[1]; + out.err = errfd; + + pid = child_execute_job (&out, 1, command_argv, envp); + } + + if (pid < 0) + { + perror_with_name (error_prefix, "fork"); + return o; + } +#endif + + { + char *buffer; + unsigned int maxlen, i; + int cc; + + /* Record the PID for reap_children. */ + shell_function_pid = pid; +#ifndef __MSDOS__ + shell_function_completed = 0; + + /* Free the storage only the child needed. */ + free (command_argv[0]); + free (command_argv); + + /* Close the write side of the pipe. We test for -1, since + pipedes[1] is -1 on MS-Windows, and some versions of MS + libraries barf when 'close' is called with -1. */ + if (pipedes[1] >= 0) + close (pipedes[1]); +#endif + + /* Set up and read from the pipe. */ + + maxlen = 200; + buffer = xmalloc (maxlen + 1); + + /* Read from the pipe until it gets EOF. */ + for (i = 0; ; i += cc) + { + if (i == maxlen) + { + maxlen += 512; + buffer = xrealloc (buffer, maxlen + 1); + } + + EINTRLOOP (cc, read (pipedes[0], &buffer[i], maxlen - i)); + if (cc <= 0) + break; + } + buffer[i] = '\0'; + + /* Close the read side of the pipe. */ +#ifdef __MSDOS__ + if (fpipe) + { + int st = pclose (fpipe); + shell_completed (st, 0); + } +#else +# ifdef _MSC_VER /* Avoid annoying msvcrt when debugging. (bird) */ + if (pipedes[0] != -1) +# endif + (void) close (pipedes[0]); +#endif + + /* Loop until child_handler or reap_children() sets + shell_function_completed to the status of our child shell. */ + while (shell_function_completed == 0) + reap_children (1, 0); + + if (batch_filename) + { + DB (DB_VERBOSE, (_("Cleaning up temporary batch file %s\n"), + batch_filename)); + remove (batch_filename); + free (batch_filename); + } + shell_function_pid = 0; + + /* shell_completed() will set shell_function_completed to 1 when the + child dies normally, or to -1 if it dies with status 127, which is + most likely an exec fail. */ + + if (shell_function_completed == -1) + { + /* This likely means that the execvp failed, so we should just + write the error message in the pipe from the child. */ + fputs (buffer, stderr); + fflush (stderr); + } + else + { + /* The child finished normally. Replace all newlines in its output + with spaces, and put that in the variable output buffer. */ + fold_newlines (buffer, &i, trim_newlines); + o = variable_buffer_output (o, buffer, i); + } + + free (buffer); + } + + return o; +} + +#else /* _AMIGA */ + +/* Do the Amiga version of func_shell. */ + +char * +func_shell_base (char *o, char **argv, int trim_newlines) +{ + /* Amiga can't fork nor spawn, but I can start a program with + redirection of my choice. However, this means that we + don't have an opportunity to reopen stdout to trap it. Thus, + we save our own stdout onto a new descriptor and dup a temp + file's descriptor onto our stdout temporarily. After we + spawn the shell program, we dup our own stdout back to the + stdout descriptor. The buffer reading is the same as above, + except that we're now reading from a file. */ + +#include +#include + + BPTR child_stdout; + char tmp_output[FILENAME_MAX]; + unsigned int maxlen = 200, i; + int cc; + char * buffer, * ptr; + char ** aptr; + int len = 0; + char* batch_filename = NULL; + + /* Construct the argument list. */ + command_argv = construct_command_argv (argv[0], NULL, NULL, 0, + &batch_filename); + if (command_argv == 0) + return o; + + /* Note the mktemp() is a security hole, but this only runs on Amiga. + Ideally we would use output_tmpfile(), but this uses a special + Open(), not fopen(), and I'm not familiar enough with the code to mess + with it. */ + strcpy (tmp_output, "t:MakeshXXXXXXXX"); + mktemp (tmp_output); + child_stdout = Open (tmp_output, MODE_NEWFILE); + + for (aptr=command_argv; *aptr; aptr++) + len += strlen (*aptr) + 1; + + buffer = xmalloc (len + 1); + ptr = buffer; + + for (aptr=command_argv; *aptr; aptr++) + { + strcpy (ptr, *aptr); + ptr += strlen (ptr) + 1; + *ptr ++ = ' '; + *ptr = 0; + } + + ptr[-1] = '\n'; + + Execute (buffer, NULL, child_stdout); + free (buffer); + + Close (child_stdout); + + child_stdout = Open (tmp_output, MODE_OLDFILE); + + buffer = xmalloc (maxlen); + i = 0; + do + { + if (i == maxlen) + { + maxlen += 512; + buffer = xrealloc (buffer, maxlen + 1); + } + + cc = Read (child_stdout, &buffer[i], maxlen - i); + if (cc > 0) + i += cc; + } while (cc > 0); + + Close (child_stdout); + + fold_newlines (buffer, &i, trim_newlines); + o = variable_buffer_output (o, buffer, i); + free (buffer); + return o; +} +#endif /* _AMIGA */ + +static char * +func_shell (char *o, char **argv, const char *funcname UNUSED) +{ + return func_shell_base (o, argv, 1); +} +#endif /* !VMS */ + +#ifdef EXPERIMENTAL + +/* + equality. Return is string-boolean, i.e., the empty string is false. + */ +static char * +func_eq (char *o, char **argv, const char *funcname UNUSED) +{ + int result = ! strcmp (argv[0], argv[1]); + o = variable_buffer_output (o, result ? "1" : "", result); + return o; +} + + +/* + string-boolean not operator. + */ +static char * +func_not (char *o, char **argv, const char *funcname UNUSED) +{ + const char *s = argv[0]; + int result = 0; + NEXT_TOKEN (s); + result = ! (*s); + o = variable_buffer_output (o, result ? "1" : "", result); + return o; +} +#endif + + +#ifdef HAVE_DOS_PATHS +# ifdef __CYGWIN__ +# define IS_ABSOLUTE(n) ((n[0] && n[1] == ':') || STOP_SET (n[0], MAP_DIRSEP)) +# else +# define IS_ABSOLUTE(n) (n[0] && n[1] == ':') +# endif +# define ROOT_LEN 3 +#else +#define IS_ABSOLUTE(n) (n[0] == '/') +#define ROOT_LEN 1 +#endif + +/* Return the absolute name of file NAME which does not contain any '.', + '..' components nor any repeated path separators ('/'). */ +#ifdef KMK +char * +#else +static char * +#endif +abspath (const char *name, char *apath) +{ + char *dest; + const char *start, *end, *apath_limit; + unsigned long root_len = ROOT_LEN; + + if (name[0] == '\0' || apath == NULL) + return NULL; + +#ifdef WINDOWS32 /* bird */ + dest = unix_slashes_resolved (name, apath, GET_PATH_MAX); + if (!dest) + return NULL; + dest = strchr(apath, '\0'); + + (void)end; (void)start; (void)apath_limit; + +#elif defined __OS2__ /* bird */ + if (_abspath(apath, name, GET_PATH_MAX)) + return NULL; + dest = strchr(apath, '\0'); + + (void)end; (void)start; (void)apath_limit; (void)dest; + +#else /* !WINDOWS32 && !__OS2__ */ + apath_limit = apath + GET_PATH_MAX; + + if (!IS_ABSOLUTE(name)) + { + /* It is unlikely we would make it until here but just to make sure. */ + if (!starting_directory) + return NULL; + + strcpy (apath, starting_directory); + +#ifdef HAVE_DOS_PATHS + if (STOP_SET (name[0], MAP_DIRSEP)) + { + if (STOP_SET (name[1], MAP_DIRSEP)) + { + /* A UNC. Don't prepend a drive letter. */ + apath[0] = name[0]; + apath[1] = name[1]; + root_len = 2; + } + /* We have /foo, an absolute file name except for the drive + letter. Assume the missing drive letter is the current + drive, which we can get if we remove from starting_directory + everything past the root directory. */ + apath[root_len] = '\0'; + } +#endif + + dest = strchr (apath, '\0'); + } + else + { +#if defined(__CYGWIN__) && defined(HAVE_DOS_PATHS) + if (STOP_SET (name[0], MAP_DIRSEP)) + root_len = 1; +#endif +#ifdef KMK + memcpy (apath, name, root_len); + apath[root_len] = '\0'; + assert (strlen (apath) == root_len); +#else + strncpy (apath, name, root_len); + apath[root_len] = '\0'; +#endif + dest = apath + root_len; + /* Get past the root, since we already copied it. */ + name += root_len; +#ifdef HAVE_DOS_PATHS + if (! STOP_SET (apath[root_len - 1], MAP_DIRSEP)) + { + /* Convert d:foo into d:./foo and increase root_len. */ + apath[2] = '.'; + apath[3] = '/'; + dest++; + root_len++; + /* strncpy above copied one character too many. */ + name--; + } + else + apath[root_len - 1] = '/'; /* make sure it's a forward slash */ +#endif + } + + for (start = end = name; *start != '\0'; start = end) + { + unsigned long len; + + /* Skip sequence of multiple path-separators. */ + while (STOP_SET (*start, MAP_DIRSEP)) + ++start; + + /* Find end of path component. */ + for (end = start; ! STOP_SET (*end, MAP_DIRSEP|MAP_NUL); ++end) + ; + + len = end - start; + + if (len == 0) + break; + else if (len == 1 && start[0] == '.') + /* nothing */; + else if (len == 2 && start[0] == '.' && start[1] == '.') + { + /* Back up to previous component, ignore if at root already. */ + if (dest > apath + root_len) + for (--dest; ! STOP_SET (dest[-1], MAP_DIRSEP); --dest) + ; + } + else + { + if (! STOP_SET (dest[-1], MAP_DIRSEP)) + *dest++ = '/'; + + if (dest + len >= apath_limit) + return NULL; + + dest = memcpy (dest, start, len); + dest += len; + *dest = '\0'; + } + } +#endif /* !WINDOWS32 && !__OS2__ */ + + /* Unless it is root strip trailing separator. */ + if (dest > apath + root_len && STOP_SET (dest[-1], MAP_DIRSEP)) + --dest; + + *dest = '\0'; + + return apath; +} + + +static char * +func_realpath (char *o, char **argv, const char *funcname UNUSED) +{ + /* Expand the argument. */ + const char *p = argv[0]; + const char *path = 0; + int doneany = 0; + unsigned int len = 0; + + while ((path = find_next_token (&p, &len)) != 0) + { + if (len < GET_PATH_MAX) + { + char *rp; + struct stat st; + PATH_VAR (in); + PATH_VAR (out); + + strncpy (in, path, len); + in[len] = '\0'; + +#ifdef HAVE_REALPATH + ENULLLOOP (rp, realpath (in, out)); +#else + rp = abspath (in, out); +#endif + + if (rp) + { + int r; + EINTRLOOP (r, stat (out, &st)); + if (r == 0) + { + o = variable_buffer_output (o, out, strlen (out)); + o = variable_buffer_output (o, " ", 1); + doneany = 1; + } + } + } + } + + /* Kill last space. */ + if (doneany) + --o; + + return o; +} + +static char * +func_file (char *o, char **argv, const char *funcname UNUSED) +{ + char *fn = argv[0]; + + if (fn[0] == '>') + { + FILE *fp; +#ifdef KMK_FOPEN_NO_INHERIT_MODE + const char *mode = "w" KMK_FOPEN_NO_INHERIT_MODE; +#else + const char *mode = "w"; +#endif + + /* We are writing a file. */ + ++fn; + if (fn[0] == '>') + { +#ifdef KMK_FOPEN_NO_INHERIT_MODE + mode = "a" KMK_FOPEN_NO_INHERIT_MODE; +#else + mode = "a"; +#endif + ++fn; + } + NEXT_TOKEN (fn); + + if (fn[0] == '\0') + O (fatal, *expanding_var, _("file: missing filename")); + + ENULLLOOP (fp, fopen (fn, mode)); + if (fp == NULL) + OSS (fatal, reading_file, _("open: %s: %s"), fn, strerror (errno)); + + if (argv[1]) + { + int l = strlen (argv[1]); + int nl = l == 0 || argv[1][l-1] != '\n'; + + if (fputs (argv[1], fp) == EOF || (nl && fputc ('\n', fp) == EOF)) + OSS (fatal, reading_file, _("write: %s: %s"), fn, strerror (errno)); + } + if (fclose (fp)) + OSS (fatal, reading_file, _("close: %s: %s"), fn, strerror (errno)); + } + else if (fn[0] == '<') + { + char *preo = o; + FILE *fp; + + ++fn; + NEXT_TOKEN (fn); + if (fn[0] == '\0') + O (fatal, *expanding_var, _("file: missing filename")); + + if (argv[1]) + O (fatal, *expanding_var, _("file: too many arguments")); + +#ifdef KMK_FOPEN_NO_INHERIT_MODE + ENULLLOOP (fp, fopen (fn, "r" KMK_FOPEN_NO_INHERIT_MODE)); +#else + ENULLLOOP (fp, fopen (fn, "r")); +#endif + if (fp == NULL) + { + if (errno == ENOENT) + return o; + OSS (fatal, reading_file, _("open: %s: %s"), fn, strerror (errno)); + } + + while (1) + { + char buf[1024]; + size_t l = fread (buf, 1, sizeof (buf), fp); + if (l > 0) + o = variable_buffer_output (o, buf, l); + + if (ferror (fp)) + if (errno != EINTR) + OSS (fatal, reading_file, _("read: %s: %s"), fn, strerror (errno)); + if (feof (fp)) + break; + } + if (fclose (fp)) + OSS (fatal, reading_file, _("close: %s: %s"), fn, strerror (errno)); + + /* Remove trailing newline. */ + if (o > preo && o[-1] == '\n') + if (--o > preo && o[-1] == '\r') + --o; + } + else + OS (fatal, *expanding_var, _("file: invalid file operation: %s"), fn); + + return o; +} + +static char * +func_abspath (char *o, char **argv, const char *funcname UNUSED) +{ + /* Expand the argument. */ + const char *p = argv[0]; + const char *path = 0; + int doneany = 0; + unsigned int len = 0; + + while ((path = find_next_token (&p, &len)) != 0) + { + if (len < GET_PATH_MAX) + { + PATH_VAR (in); + PATH_VAR (out); + + strncpy (in, path, len); + in[len] = '\0'; + + if (abspath (in, out)) + { + o = variable_buffer_output (o, out, strlen (out)); + o = variable_buffer_output (o, " ", 1); + doneany = 1; + } + } + } + + /* Kill last space. */ + if (doneany) + --o; + + return o; +} + +#ifdef CONFIG_WITH_ABSPATHEX +/* Same as abspath except that the current path may be given as the + 2nd argument. */ +static char * +func_abspathex (char *o, char **argv, const char *funcname UNUSED) +{ + char *cwd = argv[1]; + + /* cwd needs leading spaces chopped and may be optional, + in which case we're exactly like $(abspath ). */ + if (cwd) + while (ISBLANK (*cwd)) + cwd++; + if (!cwd || !*cwd) + o = func_abspath (o, argv, funcname); + else + { + /* Expand the argument. */ + const char *p = argv[0]; + unsigned int cwd_len = ~0U; + char *path = 0; + int doneany = 0; + unsigned int len = 0; + PATH_VAR (in); + PATH_VAR (out); + + while ((path = find_next_token (&p, &len)) != 0) + { + if (len < GET_PATH_MAX) + { +#ifdef HAVE_DOS_PATHS + if (path[0] != '/' && path[0] != '\\' && (len < 2 || path[1] != ':') && cwd) +#else + if (path[0] != '/' && cwd) +#endif + { + /* relative path, prefix with cwd. */ + if (cwd_len == ~0U) + cwd_len = strlen (cwd); + if (cwd_len + len + 1 >= GET_PATH_MAX) + continue; + memcpy (in, cwd, cwd_len); + in[cwd_len] = '/'; + memcpy (in + cwd_len + 1, path, len); + in[cwd_len + len + 1] = '\0'; + } + else + { + /* absolute path pass it as-is. */ + memcpy (in, path, len); + in[len] = '\0'; + } + + if (abspath (in, out)) + { + o = variable_buffer_output (o, out, strlen (out)); + o = variable_buffer_output (o, " ", 1); + doneany = 1; + } + } + } + + /* Kill last space. */ + if (doneany) + --o; + } + + return o; +} +#endif + +#ifdef CONFIG_WITH_XARGS +/* Create one or more command lines avoiding the max argument + length restriction of the host OS. + + The last argument is the list of arguments that the normal + xargs command would be fed from stdin. + + The first argument is initial command and it's arguments. + + If there are three or more arguments, the 2nd argument is + the command and arguments to be used on subsequent + command lines. Defaults to the initial command. + + If there are four or more arguments, the 3rd argument is + the command to be used at the final command line. Defaults + to the sub sequent or initial command . + + A future version of this function may define more arguments + and therefor anyone specifying six or more arguments will + cause fatal errors. + + Typical usage is: + $(xargs ar cas mylib.a,$(objects)) + or + $(xargs ar cas mylib.a,ar as mylib.a,$(objects)) + + It will then create one or more "ar mylib.a ..." command + lines with proper \n\t separation so it can be used when + writing rules. */ +static char * +func_xargs (char *o, char **argv, const char *funcname UNUSED) +{ + int argc; + const char *initial_cmd; + size_t initial_cmd_len; + const char *subsequent_cmd; + size_t subsequent_cmd_len; + const char *final_cmd; + size_t final_cmd_len; + const char *args; + size_t max_args; + int i; + +#ifdef ARG_MAX + /* ARG_MAX is a bit unreliable (environment), so drop 25% of the max. */ +# define XARGS_MAX (ARG_MAX - (ARG_MAX / 4)) +#else /* FIXME: update configure with a command line length test. */ +# define XARGS_MAX 10240 +#endif + + argc = 0; + while (argv[argc]) + argc++; + if (argc > 4) + O (fatal, NILF, _("Too many arguments for $(xargs)!\n")); + + /* first: the initial / default command.*/ + initial_cmd = argv[0]; + while (ISSPACE (*initial_cmd)) + initial_cmd++; + max_args = initial_cmd_len = strlen (initial_cmd); + + /* second: the command for the subsequent command lines. defaults to the initial cmd. */ + subsequent_cmd = argc > 2 && argv[1][0] != '\0' ? argv[1] : "\0"; + while (ISSPACE (*subsequent_cmd)) + subsequent_cmd++; /* gcc 7.3.0 complains "offset ‘1’ outside bounds of constant string" if constant is "" rather than "\0". */ + if (*subsequent_cmd) + { + subsequent_cmd_len = strlen (subsequent_cmd); + if (subsequent_cmd_len > max_args) + max_args = subsequent_cmd_len; + } + else + { + subsequent_cmd = initial_cmd; + subsequent_cmd_len = initial_cmd_len; + } + + /* third: the final command. defaults to the subseq cmd. */ + final_cmd = argc > 3 && argv[2][0] != '\0' ? argv[2] : "\0"; + while (ISSPACE (*final_cmd)) + final_cmd++; /* gcc 7.3.0: same complaint as for subsequent_cmd++ */ + if (*final_cmd) + { + final_cmd_len = strlen (final_cmd); + if (final_cmd_len > max_args) + max_args = final_cmd_len; + } + else + { + final_cmd = subsequent_cmd; + final_cmd_len = subsequent_cmd_len; + } + + /* last: the arguments to split up into sensible portions. */ + args = argv[argc - 1]; + + /* calc the max argument length. */ + if (XARGS_MAX <= max_args + 2) + ONN (fatal, NILF, _("$(xargs): the commands are longer than the max exec argument length. (%lu <= %lu)\n"), + (unsigned long)XARGS_MAX, (unsigned long)max_args + 2); + max_args = XARGS_MAX - max_args - 1; + + /* generate the commands. */ + i = 0; + for (i = 0; ; i++) + { + unsigned int len; + const char *iterator = args; + const char *end = args; + const char *cur; + const char *tmp; + + /* scan the arguments till we reach the end or the max length. */ + while ((cur = find_next_token(&iterator, &len)) + && (size_t)((cur + len) - args) < max_args) + end = cur + len; + if (cur && end == args) + O (fatal, NILF, _("$(xargs): command + one single arg is too much. giving up.\n")); + + /* emit the command. */ + if (i == 0) + { + o = variable_buffer_output (o, (char *)initial_cmd, initial_cmd_len); + o = variable_buffer_output (o, " ", 1); + } + else if (cur) + { + o = variable_buffer_output (o, "\n\t", 2); + o = variable_buffer_output (o, (char *)subsequent_cmd, subsequent_cmd_len); + o = variable_buffer_output (o, " ", 1); + } + else + { + o = variable_buffer_output (o, "\n\t", 2); + o = variable_buffer_output (o, (char *)final_cmd, final_cmd_len); + o = variable_buffer_output (o, " ", 1); + } + + tmp = end; + while (tmp > args && ISSPACE (tmp[-1])) /* drop trailing spaces. */ + tmp--; + o = variable_buffer_output (o, (char *)args, tmp - args); + + + /* next */ + if (!cur) + break; + args = end; + while (ISSPACE (*args)) + args++; + } + + return o; +} +#endif + +#ifdef CONFIG_WITH_STRING_FUNCTIONS +/* + $(length string) + + XXX: This doesn't take multibyte locales into account. + */ +static char * +func_length (char *o, char **argv, const char *funcname UNUSED) +{ + size_t len = strlen (argv[0]); + return math_int_to_variable_buffer (o, len); +} + +/* + $(length-var var) + + XXX: This doesn't take multibyte locales into account. + */ +static char * +func_length_var (char *o, char **argv, const char *funcname UNUSED) +{ + struct variable *var = lookup_variable (argv[0], strlen (argv[0])); + return math_int_to_variable_buffer (o, var ? var->value_length : 0); +} + +/* func_insert and func_substr helper. */ +static char * +helper_pad (char *o, size_t to_add, const char *pad, size_t pad_len) +{ + while (to_add > 0) + { + size_t size = to_add > pad_len ? pad_len : to_add; + o = variable_buffer_output (o, pad, size); + to_add -= size; + } + return o; +} + +/* + $(insert in, str[, n[, length[, pad]]]) + + XXX: This doesn't take multibyte locales into account. + */ +static char * +func_insert (char *o, char **argv, const char *funcname UNUSED) +{ + const char *in = argv[0]; + math_int in_len = (math_int)strlen (in); + const char *str = argv[1]; + math_int str_len = (math_int)strlen (str); + math_int n = 0; + math_int length = str_len; + const char *pad = " "; + size_t pad_len = 16; + size_t i; + + if (argv[2] != NULL) + { + n = math_int_from_string (argv[2]); + if (n > 0) + n--; /* one-origin */ + else if (n == 0) + n = str_len; /* append */ + else + { /* n < 0: from the end */ + n = str_len + n; + if (n < 0) + n = 0; + } + if (n > 16*1024*1024) /* 16MB */ + OS (fatal, NILF, _("$(insert ): n=%s is out of bounds\n"), argv[2]); + + if (argv[3] != NULL) + { + length = math_int_from_string (argv[3]); + if (length < 0 || length > 16*1024*1024 /* 16MB */) + OS (fatal, NILF, _("$(insert ): length=%s is out of bounds\n"), argv[3]); + + if (argv[4] != NULL) + { + const char *tmp = argv[4]; + for (i = 0; tmp[i] == ' '; i++) + /* nothing */; + if (tmp[i] != '\0') + { + pad = argv[4]; + pad_len = strlen (pad); + } + /* else: it was all default spaces. */ + } + } + } + + /* the head of the original string */ + if (n > 0) + { + if (n <= str_len) + o = variable_buffer_output (o, str, n); + else + { + o = variable_buffer_output (o, str, str_len); + o = helper_pad (o, n - str_len, pad, pad_len); + } + } + + /* insert the string */ + if (length <= in_len) + o = variable_buffer_output (o, in, length); + else + { + o = variable_buffer_output (o, in, in_len); + o = helper_pad (o, length - in_len, pad, pad_len); + } + + /* the tail of the original string */ + if (n < str_len) + o = variable_buffer_output (o, str + n, str_len - n); + + return o; +} + +/* + $(pos needle, haystack[, start]) + $(lastpos needle, haystack[, start]) + + XXX: This doesn't take multibyte locales into account. + */ +static char * +func_pos (char *o, char **argv, const char *funcname UNUSED) +{ + const char *needle = *argv[0] ? argv[0] : " "; + size_t needle_len = strlen (needle); + const char *haystack = argv[1]; + size_t haystack_len = strlen (haystack); + math_int start = 0; + const char *hit; + + if (argv[2] != NULL) + { + start = math_int_from_string (argv[2]); + if (start > 0) + start--; /* one-origin */ + else if (start < 0) + start = haystack_len + start; /* from the end */ + if (start < 0 || start + needle_len > haystack_len) + return math_int_to_variable_buffer (o, 0); + } + else if (funcname[0] == 'l') + start = haystack_len - 1; + + /* do the searching */ + if (funcname[0] != 'l') + { /* pos */ + if (needle_len == 1) + hit = strchr (haystack + start, *needle); + else + hit = strstr (haystack + start, needle); + } + else + { /* last pos */ + int ch = *needle; + size_t off = start + 1; + + hit = NULL; + while (off-- > 0) + { + if ( haystack[off] == ch + && ( needle_len == 1 + || strncmp (&haystack[off], needle, needle_len) == 0)) + { + hit = haystack + off; + break; + } + } + } + + return math_int_to_variable_buffer (o, hit ? hit - haystack + 1 : 0); +} + +/* + $(substr str, start[, length[, pad]]) + + XXX: This doesn't take multibyte locales into account. + */ +static char * +func_substr (char *o, char **argv, const char *funcname UNUSED) +{ + const char *str = argv[0]; + math_int str_len = (math_int)strlen (str); + math_int start = math_int_from_string (argv[1]); + math_int length = 0; + const char *pad = NULL; + size_t pad_len = 0; + + if (argv[2] != NULL) + { + if (argv[3] != NULL) + { + pad = argv[3]; + for (pad_len = 0; pad[pad_len] == ' '; pad_len++) + /* nothing */; + if (pad[pad_len] != '\0') + pad_len = strlen (pad); + else + { + pad = " "; + pad_len = 16; + } + } + length = math_int_from_string (argv[2]); + if (pad != NULL && length > 16*1024*1024 /* 16MB */) + OS (fatal, NILF, _("$(substr ): length=%s is out of bounds\n"), argv[2]); + if (pad != NULL && length < 0) + OS (fatal, NILF, _("$(substr ): negative length (%s) and padding doesn't mix.\n"), argv[2]); + if (length == 0) + return o; + } + + /* Note that negative start and length are used for referencing from the + end of the string. */ + if (pad == NULL) + { + if (start > 0) + start--; /* one-origin */ + else + { + start = str_len + start; + if (start <= 0) + { + if (length < 0) + return o; + start += length; + if (start <= 0) + return o; + length = start; + start = 0; + } + } + + if (start >= str_len) + return o; + if (length == 0) + length = str_len - start; + else if (length < 0) + { + if (str_len <= -length) + return o; + length += str_len; + if (length <= start) + return o; + length -= start; + } + else if (start + length > str_len) + length = str_len - start; + + o = variable_buffer_output (o, str + start, length); + } + else + { + if (start > 0) + { + start--; /* one-origin */ + if (start >= str_len) + return length ? helper_pad (o, length, pad, pad_len) : o; + if (length == 0) + length = str_len - start; + } + else + { + start = str_len + start; + if (start <= 0) + { + if (start + length <= 0) + return length ? helper_pad (o, length, pad, pad_len) : o; + o = helper_pad (o, -start, pad, pad_len); + return variable_buffer_output (o, str, length + start); + } + if (length == 0) + length = str_len - start; + } + if (start + length <= str_len) + o = variable_buffer_output (o, str + start, length); + else + { + o = variable_buffer_output (o, str + start, str_len - start); + o = helper_pad (o, start + length - str_len, pad, pad_len); + } + } + + return o; +} + +/* + $(translate string, from-set[, to-set[, pad-char]]) + + XXX: This doesn't take multibyte locales into account. + */ +static char * +func_translate (char *o, char **argv, const char *funcname UNUSED) +{ + const unsigned char *str = (const unsigned char *)argv[0]; + const unsigned char *from_set = (const unsigned char *)argv[1]; + const char *to_set = argv[2] != NULL ? argv[2] : ""; + char trans_tab[1 << CHAR_BIT]; + int i; + char ch; + + /* init the array. */ + for (i = 0; i < (1 << CHAR_BIT); i++) + trans_tab[i] = i; + + while ( (i = *from_set) != '\0' + && (ch = *to_set) != '\0') + { + trans_tab[i] = ch; + from_set++; + to_set++; + } + + if (i != '\0') + { + ch = '\0'; /* no padding == remove char */ + if (argv[2] != NULL && argv[3] != NULL) + { + ch = argv[3][0]; + if (ch && argv[3][1]) + OS (fatal, NILF, _("$(translate ): pad=`%s' expected a single char\n"), argv[3]); + if (ch == '\0') /* no char == space */ + ch = ' '; + } + while ((i = *from_set++) != '\0') + trans_tab[i] = ch; + } + + /* do the translation */ + while ((i = *str++) != '\0') + { + ch = trans_tab[i]; + if (ch) + o = variable_buffer_output (o, &ch, 1); + } + + return o; +} +#endif /* CONFIG_WITH_STRING_FUNCTIONS */ + +#ifdef CONFIG_WITH_DEFINED +/* Similar to ifdef. */ +static char * +func_defined (char *o, char **argv, const char *funcname UNUSED) +{ + struct variable *v = lookup_variable (argv[0], strlen (argv[0])); + int result = v != NULL && *v->value != '\0'; + o = variable_buffer_output (o, result ? "1" : "", result); + return o; +} +#endif /* CONFIG_WITH_DEFINED*/ + +#ifdef CONFIG_WITH_TOUPPER_TOLOWER +static char * +func_toupper_tolower (char *o, char **argv, const char *funcname) +{ + /* Expand the argument. */ + const char *p = argv[0]; + while (*p) + { + /* convert to temporary buffer */ + char tmp[256]; + unsigned int i; + if (!strcmp(funcname, "toupper")) + for (i = 0; i < sizeof(tmp) && *p; i++, p++) + tmp[i] = toupper(*p); + else + for (i = 0; i < sizeof(tmp) && *p; i++, p++) + tmp[i] = tolower(*p); + o = variable_buffer_output (o, tmp, i); + } + + return o; +} +#endif /* CONFIG_WITH_TOUPPER_TOLOWER */ + +#if defined(CONFIG_WITH_VALUE_LENGTH) && defined(CONFIG_WITH_COMPARE) + +/* Strip leading spaces and other things off a command. */ +static const char * +comp_cmds_strip_leading (const char *s, const char *e) +{ + while (s < e) + { + const char ch = *s; + if (!ISBLANK (ch) + && ch != '@' +#ifdef CONFIG_WITH_COMMANDS_FUNC + && ch != '%' +#endif + && ch != '+' + && ch != '-') + break; + s++; + } + return s; +} + +/* Worker for func_comp_vars() which is called if the comparision failed. + It will do the slow command by command comparision of the commands + when there invoked as comp-cmds. */ +static char * +comp_vars_ne (char *o, const char *s1, const char *e1, const char *s2, const char *e2, + char *ne_retval, const char *funcname) +{ + /* give up at once if not comp-cmds or comp-cmds-ex. */ + if (strcmp (funcname, "comp-cmds") != 0 + && strcmp (funcname, "comp-cmds-ex") != 0) + o = variable_buffer_output (o, ne_retval, strlen (ne_retval)); + else + { + const char * const s1_start = s1; + int new_cmd = 1; + int diff; + for (;;) + { + /* if it's a new command, strip leading stuff. */ + if (new_cmd) + { + s1 = comp_cmds_strip_leading (s1, e1); + s2 = comp_cmds_strip_leading (s2, e2); + new_cmd = 0; + } + if (s1 >= e1 || s2 >= e2) + break; + + /* + * Inner compare loop which compares one line. + * FIXME: parse quoting! + */ + for (;;) + { + const char ch1 = *s1; + const char ch2 = *s2; + diff = ch1 - ch2; + if (diff) + break; + if (ch1 == '\n') + break; + assert (ch1 != '\r'); + + /* next */ + s1++; + s2++; + if (s1 >= e1 || s2 >= e2) + break; + } + + /* + * If we exited because of a difference try to end-of-command + * comparision, e.g. ignore trailing spaces. + */ + if (diff) + { + /* strip */ + while (s1 < e1 && ISBLANK (*s1)) + s1++; + while (s2 < e2 && ISBLANK (*s2)) + s2++; + if (s1 >= e1 || s2 >= e2) + break; + + /* compare again and check that it's a newline. */ + if (*s2 != '\n' || *s1 != '\n') + break; + } + /* Break out if we exited because of EOS. */ + else if (s1 >= e1 || s2 >= e2) + break; + + /* + * Detect the end of command lines. + */ + if (*s1 == '\n') + new_cmd = s1 == s1_start || s1[-1] != '\\'; + s1++; + s2++; + } + + /* + * Ignore trailing empty lines. + */ + if (s1 < e1 || s2 < e2) + { + while (s1 < e1 && (ISBLANK (*s1) || *s1 == '\n')) + if (*s1++ == '\n') + s1 = comp_cmds_strip_leading (s1, e1); + while (s2 < e2 && (ISBLANK (*s2) || *s2 == '\n')) + if (*s2++ == '\n') + s2 = comp_cmds_strip_leading (s2, e2); + } + + /* emit the result. */ + if (s1 == e1 && s2 == e2) + o = variable_buffer_output (o, "", 1) - 1; /** @todo check why this was necessary back the... */ + else + o = variable_buffer_output (o, ne_retval, strlen (ne_retval)); + } + return o; +} + +/* + $(comp-vars var1,var2,not-equal-return) + or + $(comp-cmds cmd-var1,cmd-var2,not-equal-return) + + Compares the two variables (that's given by name to avoid unnecessary + expanding) and return the string in the third argument if not equal. + If equal, nothing is returned. + + comp-vars will to an exact comparision only stripping leading and + trailing spaces. + + comp-cmds will compare command by command, ignoring not only leading + and trailing spaces on each line but also leading one leading '@', + '-', '+' and '%' +*/ +static char * +func_comp_vars (char *o, char **argv, const char *funcname) +{ + const char *s1, *e1, *x1, *s2, *e2, *x2; + char *a1 = NULL, *a2 = NULL; + size_t l, l1, l2; + struct variable *var1 = lookup_variable (argv[0], strlen (argv[0])); + struct variable *var2 = lookup_variable (argv[1], strlen (argv[1])); + + /* the simple cases */ + if (var1 == var2) + return variable_buffer_output (o, "", 0); /* eq */ + if (!var1 || !var2) + return variable_buffer_output (o, argv[2], strlen(argv[2])); + if (var1->value == var2->value) + return variable_buffer_output (o, "", 0); /* eq */ + if ( (!var1->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR (var1)) + && (!var2->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR (var2)) ) + { + if ( var1->value_length == var2->value_length + && !memcmp (var1->value, var2->value, var1->value_length)) + return variable_buffer_output (o, "", 0); /* eq */ + + /* ignore trailing and leading blanks */ + s1 = var1->value; + e1 = s1 + var1->value_length; + while (ISBLANK (*s1)) + s1++; + while (e1 > s1 && ISBLANK (e1[-1])) + e1--; + + s2 = var2->value; + e2 = s2 + var2->value_length; + while (ISBLANK (*s2)) + s2++; + while (e2 > s2 && ISBLANK (e2[-1])) + e2--; + + if (e1 - s1 != e2 - s2) + return comp_vars_ne (o, s1, e1, s2, e2, argv[2], funcname); + if (!memcmp (s1, s2, e1 - s1)) + return variable_buffer_output (o, "", 0); /* eq */ + return comp_vars_ne (o, s1, e1, s2, e2, argv[2], funcname); + } + + /* ignore trailing and leading blanks */ + s1 = var1->value; + e1 = s1 + var1->value_length; + while (ISBLANK (*s1)) + s1++; + while (e1 > s1 && ISBLANK (e1[-1])) + e1--; + + s2 = var2->value; + e2 = s2 + var2->value_length; + while (ISBLANK (*s2)) + s2++; + while (e2 > s2 && ISBLANK (e2[-1])) + e2--; + + /* both empty after stripping? */ + if (s1 == e1 && s2 == e2) + return variable_buffer_output (o, "", 0); /* eq */ + + /* optimist. */ + if ( e1 - s1 == e2 - s2 + && !memcmp(s1, s2, e1 - s1)) + return variable_buffer_output (o, "", 0); /* eq */ + + /* compare up to the first '$' or the end. */ + x1 = var1->recursive ? memchr (s1, '$', e1 - s1) : NULL; + x2 = var2->recursive ? memchr (s2, '$', e2 - s2) : NULL; + if (!x1 && !x2) + return comp_vars_ne (o, s1, e1, s2, e2, argv[2], funcname); + + l1 = x1 ? x1 - s1 : e1 - s1; + l2 = x2 ? x2 - s2 : e2 - s2; + l = l1 <= l2 ? l1 : l2; + if (l && memcmp (s1, s2, l)) + return comp_vars_ne (o, s1, e1, s2, e2, argv[2], funcname); + + /* one or both buffers now require expanding. */ + if (!x1) + s1 += l; + else + { + s1 = a1 = allocated_variable_expand ((char *)s1 + l); + if (!l) + while (ISBLANK (*s1)) + s1++; + e1 = strchr (s1, '\0'); + while (e1 > s1 && ISBLANK (e1[-1])) + e1--; + } + + if (!x2) + s2 += l; + else + { + s2 = a2 = allocated_variable_expand ((char *)s2 + l); + if (!l) + while (ISBLANK (*s2)) + s2++; + e2 = strchr (s2, '\0'); + while (e2 > s2 && ISBLANK (e2[-1])) + e2--; + } + + /* the final compare */ + if ( e1 - s1 != e2 - s2 + || memcmp (s1, s2, e1 - s1)) + o = comp_vars_ne (o, s1, e1, s2, e2, argv[2], funcname); + else + o = variable_buffer_output (o, "", 1) - 1; /* eq */ /** @todo check why this was necessary back the... */ + if (a1) + free (a1); + if (a2) + free (a2); + return o; +} + +/* + $(comp-cmds-ex cmds1,cmds2,not-equal-return) + + Compares the two strings and return the string in the third argument + if not equal. If equal, nothing is returned. + + The comparision will be performed command by command, ignoring not + only leading and trailing spaces on each line but also leading one + leading '@', '-', '+' and '%'. +*/ +static char * +func_comp_cmds_ex (char *o, char **argv, const char *funcname) +{ + const char *s1, *e1, *s2, *e2; + size_t l1, l2; + + /* the simple cases */ + s1 = argv[0]; + s2 = argv[1]; + if (s1 == s2) + return variable_buffer_output (o, "", 0); /* eq */ + l1 = strlen (argv[0]); + l2 = strlen (argv[1]); + + if ( l1 == l2 + && !memcmp (s1, s2, l1)) + return variable_buffer_output (o, "", 0); /* eq */ + + /* ignore trailing and leading blanks */ + e1 = s1 + l1; + s1 = comp_cmds_strip_leading (s1, e1); + + e2 = s2 + l2; + s2 = comp_cmds_strip_leading (s2, e2); + + if (e1 - s1 != e2 - s2) + return comp_vars_ne (o, s1, e1, s2, e2, argv[2], funcname); + if (!memcmp (s1, s2, e1 - s1)) + return variable_buffer_output (o, "", 0); /* eq */ + return comp_vars_ne (o, s1, e1, s2, e2, argv[2], funcname); +} +#endif + +#ifdef CONFIG_WITH_DATE +# if defined (_MSC_VER) /* FIXME: !defined (HAVE_STRPTIME) */ +char *strptime(const char *s, const char *format, struct tm *tm) +{ + return (char *)"strptime is not implemented"; +} +# endif +/* Check if the string is all blanks or not. */ +static int +all_blanks (const char *s) +{ + if (!s) + return 1; + while (ISSPACE (*s)) + s++; + return *s == '\0'; +} + +/* The first argument is the strftime format string, a iso + timestamp is the default if nothing is given. + + The second argument is a time value if given. The format + is either the format from the first argument or given as + an additional third argument. */ +static char * +func_date (char *o, char **argv, const char *funcname) +{ + char *p; + char *buf; + size_t buf_size; + struct tm t; + const char *format; + + /* determin the format - use a single word as the default. */ + format = !strcmp (funcname, "date-utc") + ? "%Y-%m-%dT%H:%M:%SZ" + : "%Y-%m-%dT%H:%M:%S"; + if (!all_blanks (argv[0])) + format = argv[0]; + + /* get the time. */ + memset (&t, 0, sizeof(t)); + if (argv[0] && !all_blanks (argv[1])) + { + const char *input_format = !all_blanks (argv[2]) ? argv[2] : format; + p = strptime (argv[1], input_format, &t); + if (!p || *p != '\0') + { + OSSSS (error, NILF, _("$(%s): strptime(%s,%s,) -> %s\n"), funcname, + argv[1], input_format, p ? p : ""); + return variable_buffer_output (o, "", 0); + } + } + else + { + time_t tval; + time (&tval); + if (!strcmp (funcname, "date-utc")) + t = *gmtime (&tval); + else + t = *localtime (&tval); + } + + /* format it. note that zero isn't necessarily an error, so we'll + have to keep shut about failures. */ + buf_size = 64; + buf = xmalloc (buf_size); + while (strftime (buf, buf_size, format, &t) == 0) + { + if (buf_size >= 4096) + { + *buf = '\0'; + break; + } + buf = xrealloc (buf, buf_size <<= 1); + } + o = variable_buffer_output (o, buf, strlen (buf)); + free (buf); + return o; +} +#endif + +#ifdef CONFIG_WITH_FILE_SIZE +/* Prints the size of the specified file. Only one file is + permitted, notthing is stripped. -1 is returned if stat + fails. */ +static char * +func_file_size (char *o, char **argv, const char *funcname UNUSED) +{ + struct stat st; + if (stat (argv[0], &st)) + return variable_buffer_output (o, "-1", 2); + return math_int_to_variable_buffer (o, st.st_size); +} +#endif + +#ifdef CONFIG_WITH_WHICH +/* Checks if the specified file exists an is executable. + On systems employing executable extensions, the name may + be modified to include the extension. */ +static int func_which_test_x (char *file) +{ + struct stat st; +# if defined(WINDOWS32) || defined(__OS2__) + char *ext; + char *slash; + + /* fix slashes first. */ + slash = file; + while ((slash = strchr (slash, '\\')) != NULL) + *slash++ = '/'; + + /* straight */ + if (stat (file, &st) == 0 + && S_ISREG (st.st_mode)) + return 1; + + /* don't try add an extension if there already is one */ + ext = strchr (file, '\0'); + if (ext - file >= 4 + && ( !stricmp (ext - 4, ".exe") + || !stricmp (ext - 4, ".cmd") + || !stricmp (ext - 4, ".bat") + || !stricmp (ext - 4, ".com"))) + return 0; + + /* try the extensions. */ + strcpy (ext, ".exe"); + if (stat (file, &st) == 0 + && S_ISREG (st.st_mode)) + return 1; + + strcpy (ext, ".cmd"); + if (stat (file, &st) == 0 + && S_ISREG (st.st_mode)) + return 1; + + strcpy (ext, ".bat"); + if (stat (file, &st) == 0 + && S_ISREG (st.st_mode)) + return 1; + + strcpy (ext, ".com"); + if (stat (file, &st) == 0 + && S_ISREG (st.st_mode)) + return 1; + + return 0; + +# else + + return access (file, X_OK) == 0 + && stat (file, &st) == 0 + && S_ISREG (st.st_mode); +# endif +} + +/* Searches for the specified programs in the PATH and print + their full location if found. Prints nothing if not found. */ +static char * +func_which (char *o, char **argv, const char *funcname UNUSED) +{ + const char *path; + struct variable *path_var; + unsigned i; + int first = 1; + PATH_VAR (buf); + + path_var = lookup_variable ("PATH", 4); + if (path_var) + path = path_var->value; + else + path = "."; + + /* iterate input */ + for (i = 0; argv[i]; i++) + { + unsigned int len; + const char *iterator = argv[i]; + char *cur; + + while ((cur = find_next_token (&iterator, &len))) + { + /* if there is a separator, don't walk the path. */ + if (memchr (cur, '/', len) +#ifdef HAVE_DOS_PATHS + || memchr (cur, '\\', len) + || memchr (cur, ':', len) +#endif + ) + { + if (len + 1 + 4 < GET_PATH_MAX) /* +4 for .exe */ + { + memcpy (buf, cur, len); + buf[len] = '\0'; + if (func_which_test_x (buf)) + o = variable_buffer_output (o, buf, strlen (buf)); + } + } + else + { + const char *comp = path; + for (;;) + { + const char *src = comp; + const char *end = strchr (comp, PATH_SEPARATOR_CHAR); + size_t src_len = end ? (size_t)(end - comp) : strlen (comp); + if (!src_len) + { + src_len = 1; + src = "."; + } + if (len + src_len + 2 + 4 < GET_PATH_MAX) /* +4 for .exe */ + { + memcpy (buf, src, src_len); + buf [src_len] = '/'; + memcpy (&buf[src_len + 1], cur, len); + buf[src_len + 1 + len] = '\0'; + + if (func_which_test_x (buf)) + { + if (!first) + o = variable_buffer_output (o, " ", 1); + o = variable_buffer_output (o, buf, strlen (buf)); + first = 0; + break; + } + } + + /* next */ + if (!end) + break; + comp = end + 1; + } + } + } + } + + return variable_buffer_output (o, "", 0); +} +#endif /* CONFIG_WITH_WHICH */ + +#ifdef CONFIG_WITH_IF_CONDITIONALS + +/* Evaluates the expression given in the argument using the + same evaluator as for the new 'if' statements, except now + we don't force the result into a boolean like for 'if' and + '$(if-expr ,,)'. */ +static char * +func_expr (char *o, char **argv, const char *funcname UNUSED) +{ + o = expr_eval_to_string (o, argv[0]); + return o; +} + +/* Same as '$(if ,,)' except the first argument is evaluated + using the same evaluator as for the new 'if' statements. */ +static char * +func_if_expr (char *o, char **argv, const char *funcname UNUSED) +{ + int rc; + char *to_expand; + + /* Evaluate the condition in argv[0] and expand the 2nd or + 3rd (optional) argument according to the result. */ + rc = expr_eval_if_conditionals (argv[0], NULL); + to_expand = rc == 0 ? argv[1] : argv[2]; + if (to_expand && *to_expand) + variable_expand_string_2 (o, to_expand, -1, &o); + + return o; +} + +/* + $(select when1-cond, when1-body[,whenN-cond, whenN-body]). + */ +static char * +func_select (char *o, char **argv, const char *funcname UNUSED) +{ + int i; + + /* Test WHEN-CONDs until one matches. The check for 'otherwise[:]' + and 'default[:]' make this a bit more fun... */ + + for (i = 0; argv[i] != NULL; i += 2) + { + const char *cond = argv[i]; + int is_otherwise = 0; + + if (argv[i + 1] == NULL) + O (fatal, NILF, _("$(select ): not an even argument count\n")); + + while (ISSPACE (*cond)) + cond++; + if ( (*cond == 'o' && strncmp (cond, "otherwise", 9) == 0) + || (*cond == 'd' && strncmp (cond, "default", 7) == 0)) + { + const char *end = cond + (*cond == 'o' ? 9 : 7); + while (ISSPACE (*end)) + end++; + if (*end == ':') + do end++; + while (ISSPACE (*end)); + is_otherwise = *end == '\0'; + } + + if ( is_otherwise + || expr_eval_if_conditionals (cond, NULL) == 0 /* true */) + { + variable_expand_string_2 (o, argv[i + 1], -1, &o); + break; + } + } + + return o; +} + +#endif /* CONFIG_WITH_IF_CONDITIONALS */ + +#ifdef CONFIG_WITH_SET_CONDITIONALS +static char * +func_set_intersects (char *o, char **argv, const char *funcname UNUSED) +{ + const char *s1_cur; + unsigned int s1_len; + const char *s1_iterator = argv[0]; + + while ((s1_cur = find_next_token (&s1_iterator, &s1_len)) != 0) + { + const char *s2_cur; + unsigned int s2_len; + const char *s2_iterator = argv[1]; + while ((s2_cur = find_next_token (&s2_iterator, &s2_len)) != 0) + if (s2_len == s1_len + && strneq (s2_cur, s1_cur, s1_len) ) + return variable_buffer_output (o, "1", 1); /* found intersection */ + } + + return o; /* no intersection */ +} +#endif /* CONFIG_WITH_SET_CONDITIONALS */ + +#ifdef CONFIG_WITH_STACK + +/* Push an item (string without spaces). */ +static char * +func_stack_push (char *o, char **argv, const char *funcname UNUSED) +{ + do_variable_definition(NILF, argv[0], argv[1], o_file, f_append, 0 /* !target_var */); + return o; +} + +/* Pops an item off the stack / get the top stack element. + (This is what's tricky to do in pure GNU make syntax.) */ +static char * +func_stack_pop_top (char *o, char **argv, const char *funcname) +{ + struct variable *stack_var; + const char *stack = argv[0]; + + stack_var = lookup_variable (stack, strlen (stack) ); + if (stack_var) + { + unsigned int len; + const char *iterator = stack_var->value; + char *lastitem = NULL; + char *cur; + + while ((cur = find_next_token (&iterator, &len))) + lastitem = cur; + + if (lastitem != NULL) + { + if (strcmp (funcname, "stack-popv") != 0) + o = variable_buffer_output (o, lastitem, len); + if (strcmp (funcname, "stack-top") != 0) + { + *lastitem = '\0'; + while (lastitem > stack_var->value && ISSPACE (lastitem[-1])) + *--lastitem = '\0'; +#ifdef CONFIG_WITH_VALUE_LENGTH + stack_var->value_length = lastitem - stack_var->value; +#endif + VARIABLE_CHANGED (stack_var); + } + } + } + return o; +} +#endif /* CONFIG_WITH_STACK */ + +#if defined (CONFIG_WITH_MATH) || defined (CONFIG_WITH_NANOTS) || defined (CONFIG_WITH_FILE_SIZE) +/* outputs the number (as a string) into the variable buffer. */ +static char * +math_int_to_variable_buffer (char *o, math_int num) +{ + static const char xdigits[17] = "0123456789abcdef"; + int negative; + char strbuf[24]; /* 16 hex + 2 prefix + sign + term => 20 + or 20 dec + sign + term => 22 */ + char *str = &strbuf[sizeof (strbuf) - 1]; + + negative = num < 0; + if (negative) + num = -num; + + *str = '\0'; + + do + { +#ifdef HEX_MATH_NUMBERS + *--str = xdigits[num & 0xf]; + num >>= 4; +#else + *--str = xdigits[num % 10]; + num /= 10; +#endif + } + while (num); + +#ifdef HEX_MATH_NUMBERS + *--str = 'x'; + *--str = '0'; +#endif + + if (negative) + *--str = '-'; + + return variable_buffer_output (o, str, &strbuf[sizeof (strbuf) - 1] - str); +} +#endif /* CONFIG_WITH_MATH || CONFIG_WITH_NANOTS */ + +#ifdef CONFIG_WITH_MATH + +/* Converts a string to an integer, causes an error if the format is invalid. */ +static math_int +math_int_from_string (const char *str) +{ + const char *start; + unsigned base = 0; + int negative = 0; + math_int num = 0; + + /* strip spaces */ + while (ISSPACE (*str)) + str++; + if (!*str) + { + O (error, NILF, _("bad number: empty\n")); + return 0; + } + start = str; + + /* check for +/- */ + while (*str == '+' || *str == '-' || ISSPACE (*str)) + if (*str++ == '-') + negative = !negative; + + /* check for prefix - we do not accept octal numbers, sorry. */ + if (*str == '0' && (str[1] == 'x' || str[1] == 'X')) + { + base = 16; + str += 2; + } + else + { + /* look for a hex digit, if not found treat it as decimal */ + const char *p2 = str; + for ( ; *p2; p2++) + if (isxdigit (*p2) && !isdigit (*p2) && isascii (*p2) ) + { + base = 16; + break; + } + if (base == 0) + base = 10; + } + + /* must have at least one digit! */ + if ( !isascii (*str) + || !(base == 16 ? isxdigit (*str) : isdigit (*str)) ) + { + OS (error, NILF, _("bad number: '%s'\n"), start); + return 0; + } + + /* convert it! */ + while (*str && !ISSPACE (*str)) + { + int ch = *str++; + if (ch >= '0' && ch <= '9') + ch -= '0'; + else if (base == 16 && ch >= 'a' && ch <= 'f') + ch -= 'a' - 10; + else if (base == 16 && ch >= 'A' && ch <= 'F') + ch -= 'A' - 10; + else + { + OSNN (error, NILF, _("bad number: '%s' (base=%u, pos=%lu)\n"), start, base, (unsigned long)(str - start)); + return 0; + } + num *= base; + num += ch; + } + + /* check trailing spaces. */ + while (ISSPACE (*str)) + str++; + if (*str) + { + OS (error, NILF, _("bad number: '%s'\n"), start); + return 0; + } + + return negative ? -num : num; +} + +/* Add two or more integer numbers. */ +static char * +func_int_add (char *o, char **argv, const char *funcname UNUSED) +{ + math_int num; + int i; + + num = math_int_from_string (argv[0]); + for (i = 1; argv[i]; i++) + num += math_int_from_string (argv[i]); + + return math_int_to_variable_buffer (o, num); +} + +/* Subtract two or more integer numbers. */ +static char * +func_int_sub (char *o, char **argv, const char *funcname UNUSED) +{ + math_int num; + int i; + + num = math_int_from_string (argv[0]); + for (i = 1; argv[i]; i++) + num -= math_int_from_string (argv[i]); + + return math_int_to_variable_buffer (o, num); +} + +/* Multiply two or more integer numbers. */ +static char * +func_int_mul (char *o, char **argv, const char *funcname UNUSED) +{ + math_int num; + int i; + + num = math_int_from_string (argv[0]); + for (i = 1; argv[i]; i++) + num *= math_int_from_string (argv[i]); + + return math_int_to_variable_buffer (o, num); +} + +/* Divide an integer number by one or more divisors. */ +static char * +func_int_div (char *o, char **argv, const char *funcname UNUSED) +{ + math_int num; + math_int divisor; + int i; + + num = math_int_from_string (argv[0]); + for (i = 1; argv[i]; i++) + { + divisor = math_int_from_string (argv[i]); + if (!divisor) + { + OS (error, NILF, _("divide by zero ('%s')\n"), argv[i]); + return math_int_to_variable_buffer (o, 0); + } + num /= divisor; + } + + return math_int_to_variable_buffer (o, num); +} + + +/* Divide and return the remainder. */ +static char * +func_int_mod (char *o, char **argv, const char *funcname UNUSED) +{ + math_int num; + math_int divisor; + + num = math_int_from_string (argv[0]); + divisor = math_int_from_string (argv[1]); + if (!divisor) + { + OS (error, NILF, _("divide by zero ('%s')\n"), argv[1]); + return math_int_to_variable_buffer (o, 0); + } + num %= divisor; + + return math_int_to_variable_buffer (o, num); +} + +/* 2-complement. */ +static char * +func_int_not (char *o, char **argv, const char *funcname UNUSED) +{ + math_int num; + + num = math_int_from_string (argv[0]); + num = ~num; + + return math_int_to_variable_buffer (o, num); +} + +/* Bitwise AND (two or more numbers). */ +static char * +func_int_and (char *o, char **argv, const char *funcname UNUSED) +{ + math_int num; + int i; + + num = math_int_from_string (argv[0]); + for (i = 1; argv[i]; i++) + num &= math_int_from_string (argv[i]); + + return math_int_to_variable_buffer (o, num); +} + +/* Bitwise OR (two or more numbers). */ +static char * +func_int_or (char *o, char **argv, const char *funcname UNUSED) +{ + math_int num; + int i; + + num = math_int_from_string (argv[0]); + for (i = 1; argv[i]; i++) + num |= math_int_from_string (argv[i]); + + return math_int_to_variable_buffer (o, num); +} + +/* Bitwise XOR (two or more numbers). */ +static char * +func_int_xor (char *o, char **argv, const char *funcname UNUSED) +{ + math_int num; + int i; + + num = math_int_from_string (argv[0]); + for (i = 1; argv[i]; i++) + num ^= math_int_from_string (argv[i]); + + return math_int_to_variable_buffer (o, num); +} + +/* Compare two integer numbers. Returns make boolean (true="1"; false=""). */ +static char * +func_int_cmp (char *o, char **argv, const char *funcname) +{ + math_int num1; + math_int num2; + int rc; + + num1 = math_int_from_string (argv[0]); + num2 = math_int_from_string (argv[1]); + + funcname += sizeof ("int-") - 1; + if (!strcmp (funcname, "eq")) + rc = num1 == num2; + else if (!strcmp (funcname, "ne")) + rc = num1 != num2; + else if (!strcmp (funcname, "gt")) + rc = num1 > num2; + else if (!strcmp (funcname, "ge")) + rc = num1 >= num2; + else if (!strcmp (funcname, "lt")) + rc = num1 < num2; + else /*if (!strcmp (funcname, "le"))*/ + rc = num1 <= num2; + + return variable_buffer_output (o, rc ? "1" : "", rc); +} + +#endif /* CONFIG_WITH_MATH */ + +#ifdef CONFIG_WITH_NANOTS +/* Returns the current timestamp as nano seconds. The time + source is a high res monotone one if the platform provides + this (and we know about it). + + Tip. Use this with int-sub to profile makefile reading + and similar. */ +static char * +func_nanots (char *o, char **argv UNUSED, const char *funcname UNUSED) +{ + return math_int_to_variable_buffer (o, nano_timestamp ()); +} +#endif + +#ifdef CONFIG_WITH_OS2_LIBPATH +/* Sets or gets the OS/2 libpath variables. + + The first argument indicates which variable - BEGINLIBPATH, + ENDLIBPATH, LIBPATHSTRICT or LIBPATH. + + The second indicates whether this is a get (not present) or + set (present) operation. When present it is the new value for + the variable. */ +static char * +func_os2_libpath (char *o, char **argv, const char *funcname UNUSED) +{ + char buf[4096]; + ULONG fVar; + APIRET rc; + + /* translate variable name (first arg) */ + if (!strcmp (argv[0], "BEGINLIBPATH")) + fVar = BEGIN_LIBPATH; + else if (!strcmp (argv[0], "ENDLIBPATH")) + fVar = END_LIBPATH; + else if (!strcmp (argv[0], "LIBPATHSTRICT")) + fVar = LIBPATHSTRICT; + else if (!strcmp (argv[0], "LIBPATH")) + fVar = 0; + else + { + OS (error, NILF, _("$(libpath): unknown variable `%s'"), argv[0]); + return variable_buffer_output (o, "", 0); + } + + if (!argv[1]) + { + /* get the variable value. */ + if (fVar != 0) + { + buf[0] = buf[1] = buf[2] = buf[3] = '\0'; + rc = DosQueryExtLIBPATH (buf, fVar); + } + else + rc = DosQueryHeaderInfo (NULLHANDLE, 0, buf, sizeof(buf), QHINF_LIBPATH); + if (rc != NO_ERROR) + { + OSN (error, NILF, _("$(libpath): failed to query `%s', rc=%d"), argv[0], rc); + return variable_buffer_output (o, "", 0); + } + o = variable_buffer_output (o, buf, strlen (buf)); + } + else + { + /* set the variable value. */ + size_t len; + size_t len_max = sizeof (buf) < 2048 ? sizeof (buf) : 2048; + const char *val; + const char *end; + + if (fVar == 0) + { + O (error, NILF, _("$(libpath): LIBPATH is read-only")); + return variable_buffer_output (o, "", 0); + } + + /* strip leading and trailing spaces and check for max length. */ + val = argv[1]; + while (ISSPACE (*val)) + val++; + end = strchr (val, '\0'); + while (end > val && ISSPACE (end[-1])) + end--; + + len = end - val; + if (len >= len_max) + { + OSNN (error, NILF, _("$(libpath): The new `%s' value is too long (%d bytes, max %d)"), + argv[0], len, len_max); + return variable_buffer_output (o, "", 0); + } + + /* make a stripped copy in low memory and try set it. */ + memcpy (buf, val, len); + buf[len] = '\0'; + rc = DosSetExtLIBPATH (buf, fVar); + if (rc != NO_ERROR) + { + OSSN (error, NILF, _("$(libpath): failed to set `%s' to `%s', rc=%d"), argv[0], buf, rc); + return variable_buffer_output (o, "", 0); + } + + o = variable_buffer_output (o, "", 0); + } + return o; +} +#endif /* CONFIG_WITH_OS2_LIBPATH */ + +#if defined (CONFIG_WITH_MAKE_STATS) || defined (CONFIG_WITH_MINIMAL_STATS) +/* Retrieve make statistics. */ +static char * +func_make_stats (char *o, char **argv, const char *funcname UNUSED) +{ + char buf[512]; + int len; + + if (!argv[0] || (!argv[0][0] && !argv[1])) + { +# ifdef CONFIG_WITH_MAKE_STATS + len = sprintf (buf, "alloc-cur: %5ld/%3ld %3luMB hash: %5lu %2lu%%", + make_stats_allocations, + make_stats_reallocations, + make_stats_allocated / (1024*1024), + make_stats_ht_lookups, + (make_stats_ht_collisions * 100) / make_stats_ht_lookups); + o = variable_buffer_output (o, buf, len); +#endif + } + else + { + /* selective */ + int i; + for (i = 0; argv[i]; i++) + { + unsigned long val; + if (i != 0) + o = variable_buffer_output (o, " ", 1); + if (0) + continue; +# ifdef CONFIG_WITH_MAKE_STATS + else if (!strcmp(argv[i], "allocations")) + val = make_stats_allocations; + else if (!strcmp(argv[i], "reallocations")) + val = make_stats_reallocations; + else if (!strcmp(argv[i], "allocated")) + val = make_stats_allocated; + else if (!strcmp(argv[i], "ht_lookups")) + val = make_stats_ht_lookups; + else if (!strcmp(argv[i], "ht_collisions")) + val = make_stats_ht_collisions; + else if (!strcmp(argv[i], "ht_collisions_pct")) + val = (make_stats_ht_collisions * 100) / make_stats_ht_lookups; +#endif + else + { + o = variable_buffer_output (o, argv[i], strlen (argv[i])); + continue; + } + + len = sprintf (buf, "%ld", val); + o = variable_buffer_output (o, buf, len); + } + } + + return o; +} +#endif /* CONFIG_WITH_MAKE_STATS */ + +#ifdef CONFIG_WITH_COMMANDS_FUNC +/* Gets all the commands for a target, separated by newlines. + + This is useful when creating and checking target dependencies since + it reduces the amount of work and the memory consuption. A new prefix + character '%' has been introduced for skipping certain lines, like + for instance the one calling this function and pushing to a dep file. + Blank lines are also skipped. + + The commands function takes exactly one argument, which is the name of + the target which commands should be returned. + + The commands-sc is identical to commands except that it uses a ';' to + separate the commands. + + The commands-usr is similar to commands except that it takes a 2nd + argument that is used to separate the commands. */ +char * +func_commands (char *o, char **argv, const char *funcname) +{ + struct file *file; + static int recursive = 0; + + if (recursive) + { + OS (error, reading_file, _("$(%s ) was invoked recursivly"), funcname); + return variable_buffer_output (o, "recursive", sizeof ("recursive") - 1); + } + if (*argv[0] == '\0') + { + OS (error, reading_file, _("$(%s ) was invoked with an empty target name"), funcname); + return o; + } + recursive = 1; + + file = lookup_file (argv[0]); + if (file && file->cmds) + { + unsigned int i; + int cmd_sep_len; + struct commands *cmds = file->cmds; + const char *cmd_sep; + + if (!strcmp (funcname, "commands")) + { + cmd_sep = "\n"; + cmd_sep_len = 1; + } + else if (!strcmp (funcname, "commands-sc")) + { + cmd_sep = ";"; + cmd_sep_len = 1; + } + else /*if (!strcmp (funcname, "commands-usr"))*/ + { + cmd_sep = argv[1]; + cmd_sep_len = strlen (cmd_sep); + } + + initialize_file_variables (file, 1 /* don't search for pattern vars */); + set_file_variables (file, 1 /* early call */); + chop_commands (cmds); + + for (i = 0; i < cmds->ncommand_lines; i++) + { + char *p; + char *in, *out, *ref; + + /* Skip it if it has a '%' prefix or is blank. */ + if (cmds->lines_flags[i] & COMMAND_GETTER_SKIP_IT) + continue; + p = cmds->command_lines[i]; + while (ISBLANK (*p)) + p++; + if (*p == '\0') + continue; + + /* --- copied from new_job() in job.c --- */ + + /* Collapse backslash-newline combinations that are inside variable + or function references. These are left alone by the parser so + that they will appear in the echoing of commands (where they look + nice); and collapsed by construct_command_argv when it tokenizes. + But letting them survive inside function invocations loses because + we don't want the functions to see them as part of the text. */ + + /* IN points to where in the line we are scanning. + OUT points to where in the line we are writing. + When we collapse a backslash-newline combination, + IN gets ahead of OUT. */ + + in = out = p; + while ((ref = strchr (in, '$')) != 0) + { + ++ref; /* Move past the $. */ + + if (out != in) + /* Copy the text between the end of the last chunk + we processed (where IN points) and the new chunk + we are about to process (where REF points). */ + memmove (out, in, ref - in); + + /* Move both pointers past the boring stuff. */ + out += ref - in; + in = ref; + + if (*ref == '(' || *ref == '{') + { + char openparen = *ref; + char closeparen = openparen == '(' ? ')' : '}'; + int count; + char *p2; + + *out++ = *in++; /* Copy OPENPAREN. */ + /* IN now points past the opening paren or brace. + Count parens or braces until it is matched. */ + count = 0; + while (*in != '\0') + { + if (*in == closeparen && --count < 0) + break; + else if (*in == '\\' && in[1] == '\n') + { + /* We have found a backslash-newline inside a + variable or function reference. Eat it and + any following whitespace. */ + + int quoted = 0; + for (p2 = in - 1; p2 > ref && *p2 == '\\'; --p2) + quoted = !quoted; + + if (quoted) + /* There were two or more backslashes, so this is + not really a continuation line. We don't collapse + the quoting backslashes here as is done in + collapse_continuations, because the line will + be collapsed again after expansion. */ + *out++ = *in++; + else + { + /* Skip the backslash, newline and + any following whitespace. */ + in = next_token (in + 2); + + /* Discard any preceding whitespace that has + already been written to the output. */ + while (out > ref + && ISBLANK (out[-1])) + --out; + + /* Replace it all with a single space. */ + *out++ = ' '; + } + } + else + { + if (*in == openparen) + ++count; + + *out++ = *in++; + } + } + } + /* Some of these can be amended ($< perhaps), but we're likely to be called while the + dep expansion happens, so it would have to be on a hackish basis. sad... */ + else if (*ref == '<' || *ref == '*' || *ref == '%' || *ref == '^' || *ref == '+') + OSN (error, reading_file, _("$(%s ) does not work reliably with $%c in all cases"), funcname, *ref); + } + + /* There are no more references in this line to worry about. + Copy the remaining uninteresting text to the output. */ + if (out != in) + strcpy (out, in); + + /* --- copied from new_job() in job.c --- */ + + /* Finally, expand the line. */ + if (i) + o = variable_buffer_output (o, cmd_sep, cmd_sep_len); + o = variable_expand_for_file_2 (o, cmds->command_lines[i], ~0U, file, NULL); + + /* Skip it if it has a '%' prefix or is blank. */ + p = o; + while (ISBLANK (*o) + || *o == '@' + || *o == '-' + || *o == '+') + o++; + if (*o != '\0' && *o != '%') + o = strchr (o, '\0'); + else if (i) + o = p - cmd_sep_len; + else + o = p; + } /* for each command line */ + } + /* else FIXME: bitch about it? */ + + recursive = 0; + return o; +} +#endif /* CONFIG_WITH_COMMANDS_FUNC */ +#ifdef KMK + +/* Useful when debugging kmk and/or makefiles. */ +char * +func_breakpoint (char *o, char **argv UNUSED, const char *funcname UNUSED) +{ +#ifdef _MSC_VER + __debugbreak(); +#elif defined(__i386__) || defined(__x86__) || defined(__X86__) || defined(_M_IX86) || defined(__i386) \ + || defined(__amd64__) || defined(__x86_64__) || defined(__AMD64__) || defined(_M_X64) || defined(__amd64) +# ifdef __sun__ + __asm__ __volatile__ ("int $3\n\t"); +# else + __asm__ __volatile__ ("int3\n\t"); +# endif +#else + char *p = (char *)0; + *p = '\0'; +#endif + return o; +} + +/* umask | umask -S. */ +char * +func_get_umask (char *o, char **argv UNUSED, const char *funcname UNUSED) +{ + char sz[80]; + int off; + mode_t u; + int symbolic = 0; + const char *psz = argv[0]; + + if (psz) + { + const char *pszEnd = strchr (psz, '\0'); + strip_whitespace (&psz, &pszEnd); + + if (pszEnd != psz) + { + if ( STR_N_EQUALS (psz, pszEnd - pszEnd, "S") + || STR_N_EQUALS (psz, pszEnd - pszEnd, "-S") + || STR_N_EQUALS (psz, pszEnd - pszEnd, "symbolic") ) + symbolic = 1; + else + OSS (error, reading_file, _("$(%s ) invalid argument `%s'"), + funcname, argv[0]); + } + } + + u = g_fUMask; + assert (u == umask (g_fUMask)); + + if (symbolic) + { + off = 0; + sz[off++] = 'u'; + sz[off++] = '='; + if ((u & S_IRUSR) == 0) + sz[off++] = 'r'; + if ((u & S_IWUSR) == 0) + sz[off++] = 'w'; + if ((u & S_IXUSR) == 0) + sz[off++] = 'x'; + sz[off++] = ','; + sz[off++] = 'g'; + sz[off++] = '='; + if ((u & S_IRGRP) == 0) + sz[off++] = 'r'; + if ((u & S_IWGRP) == 0) + sz[off++] = 'w'; + if ((u & S_IXGRP) == 0) + sz[off++] = 'x'; + sz[off++] = ','; + sz[off++] = 'o'; + sz[off++] = '='; + if ((u & S_IROTH) == 0) + sz[off++] = 'r'; + if ((u & S_IWOTH) == 0) + sz[off++] = 'w'; + if ((u & S_IXOTH) == 0) + sz[off++] = 'x'; + } + else + off = sprintf (sz, "%.4o", u); + + return variable_buffer_output (o, sz, off); +} + + +/* umask 0002 | umask u=rwx,g=rwx,o=rx. */ +char * +func_set_umask (char *o, char **argv UNUSED, const char *funcname UNUSED) +{ + mode_t u; + const char *psz; + + /* Figure what kind of input this is. */ + psz = argv[0]; + while (ISBLANK (*psz)) + psz++; + + if (isdigit ((unsigned char)*psz)) + { + u = 0; + while (*psz) + { + u <<= 3; + if (*psz < '0' || *psz >= '8') + { + OSS (error, reading_file, _("$(%s ) illegal number `%s'"), funcname, argv[0]); + break; + } + u += *psz - '0'; + psz++; + } + + if (argv[1] != NULL) + OS (error, reading_file, _("$(%s ) too many arguments for octal mode"), funcname); + + umask (u); + g_fUMask = umask (u); /* Must get it again as windows modifies it. */ + } + else + { + OS (error, reading_file, _("$(%s ) symbol mode is not implemented"), funcname); + } + + return o; +} + + +/* Controls the cache in dir-bird-nt.c. */ + +char * +func_dircache_ctl (char *o, char **argv UNUSED, const char *funcname UNUSED) +{ +# ifdef KBUILD_OS_WINDOWS + const char *cmd = argv[0]; + while (ISBLANK (*cmd)) + cmd++; + if (strcmp (cmd, "invalidate") == 0) + { + if (argv[1] != NULL) + O (error, reading_file, "$(dircache-ctl invalidate) takes no parameters"); + dir_cache_invalid_all (); + } + else if (strcmp (cmd, "invalidate-and-close-dirs") == 0) + { + if (argv[1] != NULL) + O (error, reading_file, "$(dircache-ctl invalidate) takes no parameters"); + dir_cache_invalid_all_and_close_dirs (0 /*including_root*/); + } + else if (strcmp (cmd, "invalidate-missing") == 0) + { + if (argv[1] != NULL) + O (error, reading_file, "$(dircache-ctl invalidate-missing) takes no parameters"); + dir_cache_invalid_missing (); + } + else if (strcmp (cmd, "volatile") == 0) + { + size_t i; + for (i = 1; argv[i] != NULL; i++) + { + const char *dir = argv[i]; + while (ISBLANK (*dir)) + dir++; + if (*dir) + dir_cache_volatile_dir (dir); + } + } + else if (strcmp (cmd, "deleted") == 0) + { + size_t i; + for (i = 1; argv[i] != NULL; i++) + { + const char *dir = argv[i]; + while (ISBLANK (*dir)) + dir++; + if (*dir) + dir_cache_deleted_directory (dir); + } + } + else + OS (error, reading_file, "Unknown $(dircache-ctl ) command: '%s'", cmd); +# endif + return o; +} + +#endif /* KMK */ +#if defined (KMK) || defined (CONFIG_WITH_LAZY_DEPS_VARS) + +/* Helper for performer GNU make style quoting of one filename. */ + +static char * +helper_quote_make (char *o, const char *name, size_t len, int is_dep, + int is_tgt, int quote_trailing_slashes, + const char *funcname) +{ + unsigned const map_flags = MAP_BLANK + | MAP_NEWLINE + | MAP_COMMENT + | MAP_VARIABLE + | MAP_SEMI + | MAP_EQUALS + | (is_dep ? MAP_PIPE : + is_tgt ? MAP_COLON : 0); + const char *cur = name; + assert (memchr (name, '\0', len) == NULL); + if (len > 0) + { + const char * const end = &name[len]; + unsigned long len_out = 0; + const char *prev = cur; + do + { + char ch = *cur; + unsigned int flags = stopchar_map[(unsigned int)ch] & map_flags; + if (!flags) + cur++; /* likely */ + else + { + /* Flush pending output. */ + if (prev != cur) + { + o = variable_buffer_output (o, prev, cur - prev); + len_out += cur - prev; + } + + /* Dollar is quoted by duplicating the dollar: */ + if (flags & MAP_VARIABLE) + { + o = variable_buffer_output (o, "$", 1); + prev = cur++; + } + /* The rest is quoted by '\': */ + else + { + size_t const max_slashes = cur - prev; + size_t slashes = 0; + while (slashes < max_slashes && cur[1 - slashes] == '\\') + slashes++; + if (slashes) + { + o = variable_buffer_output (o, &cur[0 - slashes], slashes); + len_out += slashes; + } + o = variable_buffer_output (o, "\\", 1); + prev = cur++; + } + } + } + while ((uintptr_t)cur < (uintptr_t)end); + + /* Flush pending output. */ + if (prev != cur) + { + o = variable_buffer_output (o, prev, cur - prev); + len_out += cur - prev; + } + + /* Escape trailing slashes when needed. */ + if ( o[-1] == '\\' + && quote_trailing_slashes) + { + size_t slashes = 1; + while (slashes < len_out && o[-1 - slashes] == '\\') + slashes++; + while (slashes-- > 0) + o = variable_buffer_output (o, "\\", 1); + } + } + else + OS (error, reading_file, "%s: cannot quote empty string", funcname); + return o; +} + +# ifdef KMK + +/* Helper for func_quote_make that checks if there are more arguments + that produces output or not. */ + +static int func_quote_make_has_more_non_empty_args (char **argv) +{ + for (;;) + { + char *arg = *argv; + if (!arg) + return 0; + if (*arg) + return 1; + argv++; + } +} + +/* Takes zero or more plain strings and escapes (quotes) spaces and other + problematic characters, GNU make style. + + There is one slightly problematic aspect of using this, if the input ends + with backslashes whether or not they will be reduced or taken as-is depends + on whether they appear at the end of a line or not. They are taken as-is + when at the end of a line, otherwise they'll be subject to unescaping + (unquoting) and reduced by half. + + In addition, the quoting style differs for files on the left side and + right side of the recipe colon. Colons aren't escaped are only escaped + on the left side (target), and the pipe character is only escaped on the + right side (deps). + + For this reason there are four variants of this function. */ + +static char *func_quote_make (char *o, char **argv, const char *funcname) +{ + int const is_dep = funcname[5] == '-' && funcname[6] == 'd'; + int const is_tgt = funcname[5] == '-' && funcname[6] == 't'; + int const quote_trailing_slashes = funcname[5] == '\0' || funcname[9] == '\0'; + char * const o_initial = o; + int i; + + assert ( quote_trailing_slashes + == (!strcmp (funcname, "quote") || !strcmp (funcname, "quote-dep") || !strcmp (funcname, "quote-tgt"))); + assert (is_dep == !strncmp (funcname, "quote-dep", sizeof ("quote-dep") - 1)); + assert (is_tgt == !strncmp (funcname, "quote-tgt", sizeof ("quote-tgt") - 1)); + + for (i = 0; argv[i]; i++) + { + char *arg = argv[i]; + if (*arg) + { + /* Add space separator. */ + if (o != o_initial) + o = variable_buffer_output (o, " ", 1); + + /* Output the quoted argument: */ + if (quote_trailing_slashes) + o = helper_quote_make (o, arg, strlen (arg), is_dep, is_tgt, + quote_trailing_slashes, funcname); + else + { + char *end = strchr (arg, '\0'); + int qts = end != arg && end[-1] == '\\' + && func_quote_make_has_more_non_empty_args (&argv[i + 1]); + o = helper_quote_make (o, arg, strlen (arg), is_dep, is_tgt, + qts, funcname); + } + } + else + OS (error, reading_file, "%s: cannot munge empty string", funcname); + } + + return o; +} + +# endif /* KMK */ + +/* Worker for func_quote_shell() for escaping a string that's inside + double quotes. */ + +static char *func_escape_shell_in_dq (char *o, const char *arg, size_t len) +{ + const char *prev = arg; + while (len-- > 0) + { + char const ch = *arg; + switch (ch) + { + default: + arg++; + break; + case '!': + case '$': + case '`': + case '"': + case '\\': + case '\n': + if (prev != arg) + o = variable_buffer_output (o, prev, arg - prev); + o = variable_buffer_output (o, "\\", 1); + prev = arg; + arg++; + break; + } + } + if (prev != arg) + o = variable_buffer_output (o, prev, arg - prev); + return o; +} + +# ifdef KMK +/* quote-sh-dq */ + +static char *func_quote_shell_dq (char *o, char **argv, const char *funcname UNUSED) +{ + return func_escape_shell_in_dq (o, argv[0], strlen (argv[0])); +} +# endif + +/* Worker for func_quote_shell() for escaping a string that's inside + single quotes. */ + +static char *func_escape_shell_in_sq (char *o, const char *arg, size_t len) +{ + while (len > 0) + { + char *sq = memchr (arg, '\'', len); + if (!sq) + return variable_buffer_output (o, arg, len); + if (sq != arg) + o = variable_buffer_output (o, arg, sq - arg); + o = variable_buffer_output (o, "'\\''", 4); + + /* advance */ + sq++; + len -= sq - arg; + arg = sq; + } + return o; +} + +# ifdef KMK +/* quote-sh-dq */ + +static char *func_quote_shell_sq (char *o, char **argv, const char *funcname UNUSED) +{ + return func_escape_shell_in_sq (o, argv[0], strlen (argv[0])); +} +#endif + +/* Output a shell argument with quoting as needed. */ +static char *helper_quote_shell (char *o, const char *arg, size_t len, + int leading_space) +{ + if ( memchr (arg, '$', len) != NULL + || memchr (arg, '*', len) != NULL + || memchr (arg, '?', len) != NULL + || memchr (arg, '[', len) != NULL) + { + if (leading_space) + o = variable_buffer_output (o, " '", 2); + else + o = variable_buffer_output (o, "'", 1); + o = func_escape_shell_in_sq (o, arg, len); + o = variable_buffer_output (o, "'", 1); + } + else if ( memchr (arg, ' ', len) != NULL + || memchr (arg, '\t', len) != NULL + || memchr (arg, '\\', len) != NULL + || memchr (arg, '"', len) != NULL + || memchr (arg, '`', len) != NULL + || memchr (arg, '!', len) != NULL + || memchr (arg, '|', len) != NULL + || memchr (arg, '<', len) != NULL + || memchr (arg, '>', len) != NULL + || memchr (arg, '&', len) != NULL + || memchr (arg, ';', len) != NULL + || memchr (arg, '(', len) != NULL + || memchr (arg, ')', len) != NULL + || memchr (arg, '\n', len) != NULL) + { + if (leading_space) + o = variable_buffer_output (o, " \"", 2); + else + o = variable_buffer_output (o, "\"", 1); + o = func_escape_shell_in_dq (o, arg, len); + o = variable_buffer_output (o, "\"", 1); + } + else + { + if (leading_space) + o = variable_buffer_output (o, " ", 1); + o = variable_buffer_output (o, arg, len); + } + return o; +} + +# ifdef KMK + +/* Takes zero or more plain strings and escapes/quotes spaces and other + problematic characters, bourne make style. + + The quote-sh-dq and quote-sh-sq variants is for escaping strings that + going to be put into double quotes and single quotes respectively. + + The normal quote-sh variant assumes it's free to do open and close + quotes as it pleases. */ + +static char *func_quote_shell (char *o, char **argv, const char *funcname UNUSED) +{ + int i; + for (i = 0; argv[i]; i++) + o = helper_quote_shell (o, argv[i], strlen (argv[i]), + i > 0 /*need_leading_space*/); + return o; +} + +/* Unlinks CUR from *CHAINP and frees it, returning the next element. */ + +static struct nameseq * +helper_unlink_and_free_ns (struct nameseq *cur, struct nameseq *prev, + struct nameseq **chainp) +{ + struct nameseq *freeit = cur; \ + free ((char *)cur->name); + if (prev) + prev->next = cur = cur->next; + else + *chainp = cur = cur->next; + free_ns (freeit); + return cur; +} + +/* Frees a chain returned by helper_parse_file_list. */ + +static void free_ns_chain_no_strcache (struct nameseq *ns) +{ + while (ns != 0) + { + struct nameseq *t = ns; + free ((char *)ns->name); + ns = ns->next; + free_ns (t); + } +} + +# endif /* KMK */ + +/* Decoded style options for the $(q* ) and $(*file* ) functions. */ +#define Q_RET_MASK 0x000f +#define Q_RET_QUOTED 0x0000 +#define Q_RET_QUOTED_DEP 0x0001 +#define Q_RET_QUOTED_DEP_END 0x0002 +#define Q_RET_QUOTED_TGT 0x0003 +#define Q_RET_QUOTED_TGT_END 0x0004 +#define Q_RET_UNQUOTED 0x0005 +#define Q_RET_SHELL 0x0006 +#define Q_RET_SHELL_IN_DQ 0x0007 +#define Q_RET_SHELL_IN_SQ 0x0008 + +#define Q_IN_MASK 0x0070 +#define Q_IN_QUOTED 0x0000 +#define Q_IN_UNQUOTED 0x0010 +#define Q_IN_QUOTED_DEP 0x0020 /** @todo needed? */ +#define Q_IN_QUOTED_TGT 0x0030 /** @todo needed? */ +#define Q_IN_UNQUOTED_SINGLE 0x0040 +#define Q_IN_SEP_COMMA 0x0080 /* for VMS hacks, file lists only */ + +#define Q_SEP_MASK 0x0700 +#define Q_SEP_SHIFT 8 +#define Q_SEP_SPACE 0x0000 +#define Q_SEP_TAB 0x0100 +#define Q_SEP_NL 0x0200 +#define Q_SEP_NL_TAB 0x0300 +#define Q_SEP_COMMA 0x0400 /* for VMS, output only */ + +#define Q_QDEFAULT (Q_IN_QUOTED | Q_RET_QUOTED | Q_SEP_SPACE) +#ifndef VMS +# define Q_QDEFAULT_VMS_TRICKS Q_QDEFAULT +#else /* VMS: Treat ',' as file separators in input, maybe output too. */ +# define Q_QDEFAULT_VMS_TRICKS (Q_IN_SEP_COMMA | \ + (!vms_comma_separator ? Q_QDEFAULT \ + : (Q_QDEFAULT & ~Q_SEP_MASK) | Q_SEP_COMMA) +#endif + +# ifdef KMK +/* Decodes the optional style argument. This is chiefly for the return + style, but can also pick the input and space styles (just because we can). */ + +static unsigned int helper_file_quoting_style (char *style, unsigned int intstyle) +{ + if (style != NULL) + { + for (;;) + { + /* Skip blanks: */ + while (ISBLANK (*style)) + style++; + if (*style != '\0') + { + /* Find the end of the current word: */ + char * const start = style; + size_t len; + char ch; + while (!ISBLANK ((ch = *style)) && ch != '\0') + style++; + len = style - start; + + /* String "switch" to decode the word: */ + +#define MATCH(a_str) (len == sizeof (a_str) - 1 && memcmp (start, a_str, sizeof (a_str)) == 0) + /* return styles: */ + if (MATCH ("quoted") || MATCH ("q")) + intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_QUOTED; + else if (MATCH ("unquoted") || MATCH ("unq") || MATCH ("u")) + intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_UNQUOTED; + else if (MATCH ("quoted-dep") || MATCH ("q-dep") || MATCH ("q-d")) + intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_QUOTED_DEP; + else if (MATCH ("quoted-dep-end") || MATCH ("q-dep-end") || MATCH ("q-d-e")) + intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_QUOTED_DEP_END; + else if (MATCH ("quoted-tgt") || MATCH ("q-tgt") || MATCH ("q-t")) + intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_QUOTED_TGT; + else if (MATCH ("quoted-tgt-end") || MATCH ("q-tgt-end") || MATCH ("q-t-e")) + intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_QUOTED_TGT_END; + else if (MATCH ("shell") || MATCH ("sh")) + intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_SHELL; + else if (MATCH ("shell-in-dq") || MATCH ("sh-i-d")) + intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_SHELL_IN_DQ; /* returned string is used inside double shell quotes */ + else if (MATCH ("shell-in-sq") || MATCH ("sh-i-s")) + intstyle = (intstyle & ~Q_RET_MASK) | Q_RET_SHELL_IN_SQ; /* returned string is used inside single shell quotes */ + /* input styles: */ + else if (MATCH ("in-quoted") || MATCH ("i-q")) + intstyle = (intstyle & ~Q_IN_MASK) | Q_IN_QUOTED; + else if (MATCH ("in-unquoted") || MATCH ("i-unq") || MATCH ("i-u")) + intstyle = (intstyle & ~Q_IN_MASK) | Q_IN_UNQUOTED; + else if (MATCH ("in-unquoted-single")|| MATCH ("i-unq-s") || MATCH ("i-u-s") + || MATCH ("in-unquoted-file") || MATCH ("i-unq-f") || MATCH ("i-u-f")) + intstyle = (intstyle & ~Q_IN_MASK) | Q_IN_UNQUOTED_SINGLE; + else if (MATCH ("in-quoted-dep") || MATCH ("i-q-dep") || MATCH ("i-q-d")) + intstyle = (intstyle & ~Q_IN_MASK) | Q_IN_QUOTED_DEP; + else if (MATCH ("in-quoted-tgt") || MATCH ("i-q-tgt") || MATCH ("i-q-t")) + intstyle = (intstyle & ~Q_IN_MASK) | Q_IN_QUOTED_TGT; + else if (MATCH ("in-sep-comma") || MATCH ("i-s-com") || MATCH ("i-s-c")) + intstyle |= Q_IN_SEP_COMMA; /*?*/ + /* separator styles (output): */ + else if (MATCH ("sep-space") || MATCH ("s-space") || MATCH ("s-s")) + intstyle = (intstyle & ~Q_SEP_MASK) | Q_SEP_SPACE; + else if (MATCH ("sep-tab") || MATCH ("s-tab") || MATCH ("s-t")) + intstyle = (intstyle & ~Q_SEP_MASK) | Q_SEP_TAB; + else if (MATCH ("sep-nl") || MATCH ("s-nl") || MATCH ("s-n")) + intstyle = (intstyle & ~Q_SEP_MASK) | Q_SEP_NL; + else if (MATCH ("sep-nl-tab") || MATCH ("s-nl-tab") || MATCH ("s-n-t")) + intstyle = (intstyle & ~Q_SEP_MASK) | Q_SEP_NL_TAB; + else if (MATCH ("sep-comma") || MATCH ("s-comma") || MATCH ("s-c")) + intstyle = (intstyle & ~Q_SEP_MASK) | Q_SEP_COMMA; + else + { + char savedch = *style; + *style = '\0'; + OS (error, reading_file, "Unknown file style: %s", start); + *style = savedch; + } +#undef MATCH + } + else + break; + } + } + return intstyle; +} +# endif /* KMK */ + +/* Output (returns) a separator according to STYLE. */ + +static char *helper_return_sep (char *o, unsigned int style) +{ + /* Note! Must match Q_SEP_MASK! */ + static struct + { + const char *sep; + size_t len; + } const seps[8] = + { + { " ", 1 }, + { "\t", 1 }, + { "\n", 1 }, + { "\n\t", 2 }, + { ",", 1 }, + { " ", 1 }, + { " ", 1 }, + { " ", 1 } + }; + + return variable_buffer_output(o, + seps[(style & Q_SEP_MASK) >> Q_SEP_SHIFT].sep, + seps[(style & Q_SEP_MASK) >> Q_SEP_SHIFT].len); +} + +/* Removes one separator from the output. + +This is typically used when outputting lists where there is no simple way of +telling whether an entry is the last one or not. So, is_last is always false +and the last separator is removed afterwards by this function. */ + +MY_INLINE char *helper_drop_separator (char *o, unsigned int style) +{ + o -= (style & Q_SEP_MASK) != Q_SEP_NL_TAB ? 1 : 2; + *o = '\0'; /* not strictly necessary */ + return o; +} + + +/* Outputs (returns) the given file. */ + +static char *helper_return_file_len (char *o, const char *file, size_t len, + unsigned int style, int is_last) +{ + assert (memchr (file, '\0', len) == NULL); + switch (style & Q_RET_MASK) + { + case Q_RET_UNQUOTED: + o = variable_buffer_output (o, file, len); + break; + case Q_RET_QUOTED: + o = helper_quote_make (o, file, len, 0 /*is_dep*/, 0 /*is_tgt*/, + !is_last /*quote_trailing_slashes*/, NULL); + break; + case Q_RET_QUOTED_DEP: + o = helper_quote_make (o, file, len, 1 /*is_dep*/, 0 /*is_tgt*/, + !is_last /*quote_trailing_slashes*/, NULL); + break; + case Q_RET_QUOTED_DEP_END: + o = helper_quote_make (o, file, len, 1 /*is_dep*/, 0 /*is_tgt*/, + 0 /*quote_trailing_slashes*/, NULL); + break; + case Q_RET_QUOTED_TGT: + o = helper_quote_make (o, file, len, 0 /*is_dep*/, 1 /*is_tgt*/, + !is_last /*quote_trailing_slashes*/, NULL); + break; + case Q_RET_QUOTED_TGT_END: + o = helper_quote_make (o, file, len, 0 /*is_dep*/, 1 /*is_tgt*/, + 0 /*quote_trailing_slashes*/, NULL); + break; + case Q_RET_SHELL: + o = helper_quote_shell (o, file, len, 0 /*need_leading_space*/); + break; + case Q_RET_SHELL_IN_DQ: + o = func_escape_shell_in_dq (o, file, len); + break; + case Q_RET_SHELL_IN_SQ: + o = func_escape_shell_in_sq (o, file, len); + break; + default: + assert (0); + } + + /* Add separator space if not last. */ + if (!is_last) + o = helper_return_sep (o, style); + return o; +} + +/* Outputs (returns) the given file. */ + +static char *helper_return_file (char *o, const char *file, + unsigned int style, int is_last) +{ + return helper_return_file_len (o,file, strlen (file), style, is_last); +} + +#endif /* KMK || CONFIG_WITH_LAZY_DEPS_VARS */ +#ifdef KMK + +/* Outputs (returns) the given CHAIN and frees it. */ + +static char *helper_return_and_free_chain (char *o, struct nameseq *chain, unsigned int style) +{ + struct nameseq *cur; + for (cur = chain; cur; cur = cur->next) + o = helper_return_file (o, cur->name, style, cur->next == NULL); + free_ns_chain_no_strcache (chain); + return o; +} + + +/* Helper for helper_parse_file_list that globs a name sequence. */ +static struct nameseq * +helper_glob_chain (struct nameseq *chain) +{ + struct nameseq *prev = NULL; + struct nameseq *cur = chain; + glob_t gl; + dir_setup_glob (&gl); + + /** @todo XXX: !NO_ARCHIVES */ + while (cur) + { + switch (glob (cur->name, GLOB_NOSORT | GLOB_ALTDIRFUNC, NULL, &gl)) + { + case 0: /* Replace CUR with the names found. */ + { + struct nameseq *subchain = NULL; + struct nameseq **ppnext = &subchain; + const char ** const names = (const char **)gl.gl_pathv; + size_t const num_names = gl.gl_pathc; + size_t idx; + + cur = helper_unlink_and_free_ns (cur, prev, &chain); + + for (idx = 0; idx < num_names; idx++) + { +#ifndef CONFIG_WITH_ALLOC_CACHES + struct nameseq *newp = xcalloc (sizeof (*newp)); +#else + struct nameseq *newp = alloccache_calloc (&nameseq_cache); +#endif + newp->name = xstrdup (names[idx]); + newp->next = NULL; + *ppnext = newp; + ppnext = &newp->next; + } + + if (subchain) /* parnaoia */ + { + *ppnext = cur; + if (prev) + prev->next = subchain; + else + chain = subchain; + } + break; + } + + case GLOB_NOMATCH: /* doesn't exist, remove */ + cur = helper_unlink_and_free_ns (cur, prev, &chain); + break; + + default: /* Keep it. */ + prev = cur; + cur = cur->next; + break; + + case GLOB_NOSPACE: + OUT_OF_MEM(); + } + globfree (&gl); + } + return chain; +} + +/* Parses a file/word list according to STYLE and returns a name list. + + The FILELIST parameter may be modified! + + The GLOB param is for wildcard/qwildcard. + + TODO/XXX: Unquote and split up the FILELIST directly. All function + arguments are heap copies already, so we are free to modify + them. Would be nice to ditch the nameseq in favor of something + which also includes the length. */ + +static struct nameseq * +helper_parse_file_list (char *filelist, unsigned int style, int glob) +{ + if (filelist && *filelist != '\0') + { + /* Q_IN_SEP_COMMA: VMS tricks for qbasename, qdir, qnotdir and qsuffix + where commas are treated as separtors in FILELIST. We simply + replace commas in the FILELIST before doing the regular parsing. */ + if (!(style & Q_IN_SEP_COMMA)) + { /* typical */ } + else + { + size_t len = strlen (filelist); + char *start = filelist; + char *comma = (char *)memchr (filelist, ',', len); + while (comma) + { + *comma = ' '; + len -= comma - start - 1; + if (len) + { + start = comma + 1; + comma = (char *)memchr (start, ',', len); + } + else + break; + } + } + + switch (style & Q_IN_MASK) + { + case Q_IN_QUOTED: + case Q_IN_QUOTED_DEP: /** @todo ?? */ + case Q_IN_QUOTED_TGT: /** @todo ?? */ + return PARSE_FILE_SEQ(&filelist, struct nameseq, MAP_NUL, NULL, + !glob + ? PARSEFS_NOGLOB | PARSEFS_NOSTRIP | PARSEFS_NOCACHE + : PARSEFS_NOSTRIP | PARSEFS_NOCACHE | PARSEFS_EXISTS); + + case Q_IN_UNQUOTED: + { + struct nameseq *chain = NULL; + struct nameseq **ppnext = &chain; + const char *it = filelist; + const char *cur; + unsigned int curlen; + while ((cur = find_next_token (&it, &curlen)) != NULL) + { +#ifndef CONFIG_WITH_ALLOC_CACHES + struct nameseq *newp = xcalloc (sizeof (*newp)); +#else + struct nameseq *newp = alloccache_calloc (&nameseq_cache); +#endif + newp->name = xstrndup (cur, curlen); + newp->next = NULL; + *ppnext = newp; + ppnext = &newp->next; + } + if (!glob) + return chain; + return helper_glob_chain (chain); + } + + case Q_IN_UNQUOTED_SINGLE: + if (*filelist != '\0') + { +#ifndef CONFIG_WITH_ALLOC_CACHES + struct nameseq *newp = xcalloc (sizeof (*newp)); +#else + struct nameseq *newp = alloccache_calloc (&nameseq_cache); +#endif + newp->name = xstrdup (filelist); + newp->next = NULL; + if (!glob) + return newp; + return helper_glob_chain (newp); + } + return NULL; + + default: + assert (0); + return NULL; + } + } + return NULL; +} + +/* $(requote style, file1 file2 ... fileN). */ + +static char *func_requote (char *o, char **argv, const char *funcname UNUSED) +{ + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT); + struct nameseq *chain = helper_parse_file_list (argv[1], style, 0); + return helper_return_and_free_chain (o, chain, style); +} + +/* Common worker for func_firstfile() and func_qfirstfile(). */ + +static char *common_firstfile (char *o, char **argv, unsigned int style) +{ + struct nameseq *chain = helper_parse_file_list (argv[0], style, 0); + if (chain) + { + o = helper_return_file (o, chain->name, style, 1); + free_ns_chain_no_strcache (chain); + } + return o; +} + +/* $(firstfile file1 file2 ... fileN) - same as $(firstfile ), except + for files rather than word tokens. See func_firstword(). */ + +static char *func_firstfile (char *o, char **argv, const char *funcname UNUSED) +{ + return common_firstfile(o, argv, Q_IN_QUOTED | Q_RET_QUOTED | Q_SEP_SPACE); +} + +/* $(qfirstfile style, file1 file2 ... fileN) - same as $(firstfile ), except + for files rather than word tokens. See func_firstword(). */ + +static char *func_q_firstfile (char *o, char **argv, const char *funcname UNUSED) +{ + unsigned int style = helper_file_quoting_style (argv[0], Q_QDEFAULT); + return common_firstfile(o, &argv[1], style); +} + +/* Common worker for func_lastfile() and func_q_lastfile(). */ + +static char *common_lastfile (char *o, char **argv, unsigned int style) +{ + struct nameseq *chain = helper_parse_file_list (argv[0], style, 0); + if (chain) + { + struct nameseq *last = chain; + while (last->next) + last = last->next; + o = helper_return_file (o, last->name, style, 1); + free_ns_chain_no_strcache (chain); + } + return o; +} + +/* $(lastfile file1 file2 ... fileN) - same as $(lastfile ), except + for files rather than word tokens. See func_lastword(). */ + +static char *func_lastfile (char *o, char **argv, const char *funcname UNUSED) +{ + return common_lastfile (o, argv, Q_IN_QUOTED | Q_RET_QUOTED | Q_SEP_SPACE); +} + +/* $(qlastfile style, file1 file2 ... fileN) - same as $(lastfile ), except + for files rather than word tokens. See func_lastword(). */ + +static char *func_q_lastfile (char *o, char **argv, const char *funcname UNUSED) +{ + unsigned int style = helper_file_quoting_style (argv[0], Q_QDEFAULT); + return common_lastfile (o, &argv[1], style); +} + +/* Common worker for func_filelist() and func_q_filelist(). */ + +static char *common_filelist (char *o, char **argv, unsigned int style) +{ + int start; + int count; + + /* Check the arguments. */ + check_numeric (argv[0], + _("non-numeric first argument to 'filelist' function")); + check_numeric (argv[1], + _("non-numeric second argument to 'filelist' function")); + + start = atoi (argv[0]); + if (start < 1) + ON (fatal, *expanding_var, + "invalid first argument to 'filelist' function: '%d'", start); + start--; /* make zero based */ + + count = atoi (argv[1]) - start; + + if (count > 0) + { + char *line = argv[2]; + struct nameseq *cur; + struct nameseq *chain; + chain = helper_parse_file_list (line, style, 0); + + /* Find the beginning of the "start"th word (1-based). */ + for (cur = chain; cur && start > 1; cur = cur->next) + start--; + + /* Output the requested count */ + while (cur && count-- > 0) + o = helper_return_file (o, cur->name, style, count > 0 && cur->next); + + free_ns_chain_no_strcache (chain); + } + + return o; +} + +/* $(filelist start, end, file1..fileN) - same as $(wordlist), + except for files rather than word tokens. See func_wordlist(). */ + +static char *func_filelist (char *o, char **argv, const char *funcname UNUSED) +{ + return common_filelist (o, argv, Q_IN_QUOTED | Q_RET_QUOTED | Q_SEP_SPACE); +} + +/* $(qfilelist style, start, end, file1..fileN) - same as $(wordlist), + except for files rather than word tokens. See func_wordlist(). */ + +static char *func_q_filelist (char *o, char **argv, const char *funcname UNUSED) +{ + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT); + return common_filelist (o, &argv[1], style); +} + +/* Common worker for func_countfiles() and func_q_countfiles(). */ + +static char *common_countfiles (char *o, char **argv, unsigned int style) +{ + struct nameseq *chain = helper_parse_file_list (argv[0], style, 0); + struct nameseq *cur; + unsigned int files = 0; + char retval[32]; + + for (cur = chain; cur; cur = cur->next) + files++; + free_ns_chain_no_strcache (chain); + + return variable_buffer_output (o, retval, sprintf (retval, "%u", files)); +} + +/* $(countfiles file1 file2 ... fileN) - same as $(words ), except for + files rather than word tokens. See func_words(). */ + +static char *func_countfiles (char *o, char **argv, const char *funcname UNUSED) +{ + return common_countfiles (o, argv, Q_IN_QUOTED | Q_RET_QUOTED | Q_SEP_SPACE); +} + +/* $(qcountfiles style, file1 file2 ... fileN) - same as $(words ), except for + files rather than word tokens and the STYLE argument. See func_words(). */ + +static char *func_q_countfiles (char *o, char **argv, const char *funcname UNUSED) +{ + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT); + return common_countfiles (o, &argv[1], style); +} + +/* Helper that sets the variable value. */ + +static void +helper_set_var_value (struct variable *var, const char *value, size_t len) +{ +#ifndef CONFIG_WITH_VALUE_LENGTH + free (var->value); + var->value = xstrndup (value, len); +#else + if (len >= var->value_alloc_len) + { +# ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE + if (var->rdonly_val) + var->rdonly_val = 0; + else +# endif + free (var->value); + var->value_alloc_len = VAR_ALIGN_VALUE_ALLOC (len + 1); + var->value = xmalloc (var->value_alloc_len); + } + memcpy (var->value, value, len); + var->value[len] = '\0'; + var->value_length = len; + VARIABLE_CHANGED (var); +#endif +} + +/* Common worker for func_foreachfile and func_qforeachfile. */ + +static char * +common_foreachfile (char *o, char **argv, unsigned int style) +{ + /* expand only the first two. */ + char *varname = expand_argument (argv[0], NULL); + char *list = expand_argument (argv[1], NULL); + const char *body = argv[2]; +#ifdef CONFIG_WITH_VALUE_LENGTH + long body_len = strlen (body); +#endif + + struct nameseq *chain = helper_parse_file_list (list, style, 0); + struct nameseq *cur; + + /* Clean up the variable name by removing whitespace. */ + struct variable *var; + char *vp = next_token (varname); + char *vp_end = end_of_token (vp); + vp_end[0] = '\0'; + + push_new_variable_scope (); + var = define_variable (vp, vp_end - vp, "", o_automatic, 0); + + /* Don't need the list any more. */ + free (list); + list = NULL; + + /* Loop through the chain. */ + for (cur = chain; cur; cur = cur->next) + { + /* Update the variable value: */ + unsigned int const len = strlen (cur->name); + switch (style & Q_RET_MASK) + { + case Q_RET_UNQUOTED: + helper_set_var_value (var, cur->name, len); + break; + default: + { /* Use the output buffer as temporary storage. */ + size_t const saved_off = o - variable_buffer; + size_t quoted_len; + char *quoted; + o = helper_return_file_len (o, cur->name, len, style, 1 /*is_last*/); + quoted = &variable_buffer[saved_off]; + quoted_len = o - quoted; + helper_set_var_value (var, quoted, quoted_len); + o = quoted; + break; + } + } + + /* Expand the body: */ +#ifndef CONFIG_WITH_VALUE_LENGTH + { + char *result = allocated_variable_expand (body); + o = variable_buffer_output (o, result, strlen (result)); + free (result); + } +#else + variable_expand_string_2 (o, body, body_len, &o); +#endif + + /* Add separator: */ + if (cur->next) + o = helper_return_sep (o, style); + } + + pop_variable_scope (); + free (varname); + + return o; +} + +/* $(foreachfile var, filelist, body) - same as $(foreach ), except + for file rather than word tokens. + See also func_foreach(). */ + +static char * +func_foreachfile (char *o, char **argv, const char *funcname UNUSED) +{ + return common_foreachfile (o, argv, Q_IN_QUOTED | Q_RET_QUOTED | Q_SEP_SPACE); +} + +/* $(qforeachfile style, var, filelist, body) - same as $(foreach ), except + for file rather than word tokens and flexible variable value encoding. + See also func_foreach(). */ + +static char * +func_q_foreachfile (char *o, char **argv, const char *funcname UNUSED) +{ + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT); + return common_foreachfile (o, &argv[1], style); +} + +/* Common worker for func_sortfiles() and func_q_sortfiles(). */ + +static char *common_sortfiles (char *o, char **argv, unsigned int style, + int ascending, int version) +{ + struct nameseq *chain = helper_parse_file_list (argv[0], style, 0); + + /* Count the number of files to determin the array size and whether we've + got anything to sort. */ + struct nameseq *cur; + unsigned int num_files = 0; + for (cur = chain; cur; cur = cur->next) + num_files++; + + if (num_files <= 1) + o = helper_return_and_free_chain (o, chain, style); + else + { + /* Create array of string pointers from the chain. */ + char **files = (char **)xmalloc (num_files * sizeof (char *)); + unsigned int idx = 0; + for (cur = chain; cur; cur = cur->next) + files[idx++] = (char *)cur->name; + + /* Sort it. */ + if (version) + qsort(files, num_files, sizeof(files[0]), version_compare_wrapper); + else + qsort(files, num_files, sizeof(files[0]), alpha_compare); + + /* Output. We skip equal files. */ + if (ascending) + for (idx = 0; idx < num_files; idx++) + { + const char *curfile = files[idx]; + while (idx + 1 < num_files && strcmp(files[idx + 1], curfile) == 0) + idx++; + o = helper_return_file(o, files[idx], style, idx + 1 >= num_files); + } + else + { + idx = num_files; + while (idx-- > 0) + { + const char *curfile = files[idx]; + while (idx > 0 && strcmp(files[idx - 1], curfile) == 0) + idx--; + o = helper_return_file (o, curfile, style, idx == 0); + } + } + + free (files); + free_ns_chain_no_strcache (chain); + } + return o; +} + +/* $(sortfiles file1 ... fileN) and + $(rsortfiles file1 ... fileN) - same as $(sort ) and $(rsort ), + except for files rather than word tokens. See func_sort(). */ + +static char *func_sortfiles (char *o, char **argv, const char *funcname) +{ + return common_sortfiles (o, argv, Q_IN_QUOTED | Q_RET_QUOTED | Q_SEP_SPACE, + funcname[0] != 'r', + funcname[0] == 'v' || funcname[1] == 'v'); +} + +/* $(qsortfiles style, file1 ... fileN) and + $(qrsortfiles style, file1 ... fileN) - same as $(sort ) and $(rsort ), + except for files rather than word tokens and the flexible style. + See func_sort(). */ + +static char *func_q_sortfiles (char *o, char **argv, const char *funcname) +{ + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT); + return common_sortfiles (o, &argv[1], style, funcname[1] != 'r', + funcname[1] == 'v' || funcname[2] == 'v'); +} + + +/* Helper for determining whether the given path is absolute or not. */ + +static int helper_is_abs (const char *path) +{ +#ifdef HAVE_DOS_PATHS + return path[0] == '/' + || path[0] == '\\' + || (isalpha(path[0]) && path[1] == ':'); +#else + return path[0] == '/'; +#endif +} + +/* Worker for func_q_abspath and func_q_abspath_ex. */ + +static char *worker_abspath (char *o, char *line, const char *cwd, + size_t cwd_len, unsigned int style) +{ + if (line && *line != '\0') + { + PATH_VAR (outbuf); + struct nameseq *chain = helper_parse_file_list (line, style, 0); + + /* Special case: single path, no cwd - no is_last path trouble */ + if (chain && !chain->next && !cwd) + { + if (abspath (chain->name, outbuf)) + o = helper_return_file(o, outbuf, style, 1); + free_ns_chain_no_strcache (chain); + } + else if (chain) + { + /* Pass one: replace names by absolute names */ + struct nameseq *prev = NULL; + struct nameseq *cur = chain; + while (cur) + { + /* If relative path and we've got cwd, join cwd and it. */ + if (cwd && !helper_is_abs (cur->name)) + { + size_t len_name = strlen (cur->name); + char *name = xrealloc ((char *)cur->name, cwd_len + 1 + len_name + 1); + memmove (&name[cwd_len + 1], &name[0], len_name); + memcpy (name, cwd, cwd_len); + name[cwd_len] = '/'; + name[cwd_len + 1 + len_name] = '\0'; + cur->name = name; + } + + if (abspath (cur->name, outbuf)) + { + free ((char *)cur->name); + cur->name = xstrdup (outbuf); + prev = cur; + cur = cur->next; + } + else /* remove it */ + cur = helper_unlink_and_free_ns (cur, prev, &chain); + } + + /* Pass two: output */ + o = helper_return_and_free_chain (o, chain, style); + } + } + return o; +} + +/* $(qabspath style, file1 file2 ... fileN) - same as $(abspath ), except + for files rather than word tokens. See func_abspath(). */ + +static char *func_q_abspath (char *o, char **argv, const char *funcname UNUSED) +{ + return worker_abspath (o, argv[1], NULL, 0, + helper_file_quoting_style (argv[0], Q_QDEFAULT)); +} + +# ifdef CONFIG_WITH_ABSPATHEX +/* $(qabspathex style, file1 file2 ... fileN [,cwd]) - same as $(abspathex ), + except for files rather than word tokens. See func_abspath_ex(). */ + +static char * +func_q_abspathex (char *o, char **argv, const char *funcname UNUSED) +{ + /* cwd needs leading spaces chopped and may be optional, + in which case we're exactly like $(abspath ). */ + char *cwd = argv[2]; + if (cwd) + { + while (ISBLANK (*cwd)) + cwd++; + if (*cwd == '\0') + cwd = NULL; + } + + return worker_abspath (o, argv[1], cwd, cwd ? strlen (cwd) : 0, + helper_file_quoting_style (argv[0], Q_QDEFAULT)); +} +# endif + +/* $(qaddprefix style, prefix, file1 ... fileN) and + $(qaddsuffix style, prefix, file1 ... fileN) - same as $(addprefix ) + and $(addsuffix ) except for files rather than word tokens. + The suffix/prefix is unquoted on input and subjected to the same quoting + styling as the file names. + See func_addsuffix_addprefix(). */ + +static char *func_q_addsuffix_addprefix (char *o, char **argv, const char *funcname UNUSED) +{ + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT); + const char * const fix = argv[1]; + size_t const fixlen = strlen (fix); + struct nameseq *chain = helper_parse_file_list (argv[2], style, 0); + if (chain) + { + size_t tmpsize = (fixlen + 512) & ~(size_t)63; + char *tmp = (char *)xmalloc (tmpsize); + struct nameseq *cur; + + if (funcname[4] == 'p') + { + memcpy (tmp, fix, fixlen); + for (cur = chain; cur; cur = cur->next) + { + size_t curlen = strlen (cur->name); + if (fixlen + curlen + 1 <= tmpsize) + { /* likely */ } + else + { + tmpsize = (fixlen + curlen + 63) & ~(size_t)63; + tmp = (char *)xrealloc (tmp, tmpsize); + } + memcpy (&tmp[fixlen], cur->name, curlen + 1); + o = helper_return_file_len (o, tmp, fixlen + curlen, + style, cur->next == NULL); + } + } + else + for (cur = chain; cur; cur = cur->next) + { + size_t curlen = strlen (cur->name); + if (fixlen + curlen + 1 <= tmpsize) + { /* likely */ } + else + { + tmpsize = (fixlen + curlen + 63) & ~(size_t)63; + tmp = (char *)xrealloc (tmp, tmpsize); + } + memcpy (tmp, cur->name, curlen); + memcpy (&tmp[curlen], fix, fixlen + 1); + + o = helper_return_file_len (o, tmp, fixlen + curlen, + style, cur->next == NULL); + } + free_ns_chain_no_strcache (chain); + } + return o; +} + +/* $(qbasename style, path1 .. pathN) and $(qdir style, path1 .. pathN) + - same as $(basename ) and $(dir ), except for files rather than word tokens. + See func_basename_dir(). */ + +static char * +func_q_basename_dir (char *o, char **argv, const char *funcname) +{ + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT_VMS_TRICKS); + struct nameseq *chain = helper_parse_file_list (argv[1], style, 0); + struct nameseq *cur; + + int const is_basename = funcname[1] == 'b'; + int const is_dir = !is_basename; + int const stop = MAP_DIRSEP | (is_basename ? MAP_DOT : 0) | MAP_NUL; + + for (cur = chain; cur; cur = cur->next) + { + int const is_last = cur->next == NULL; + const char * const path = cur->name; + const char * const end = strchr (path, '\0'); + + /* Locate the last dot or path separator (P): */ + const char *p = path != end ? end - 1 : end; + while (p >= path && !STOP_SET (*p, stop)) + --p; + + /* Do the outputting: */ + if (p >= path && (is_dir)) + o = helper_return_file_len (o, path, ++p - path, style, is_last); + else if (p >= path && *p == '.') + o = helper_return_file_len (o, path, p - path, style, is_last); +#ifdef HAVE_DOS_PATHS + /* Handle the "d:foobar" case */ + else if (path[0] && path[1] == ':' && is_dir) + o = helper_return_file_len (o, path, 2, style, is_last); +#endif + else if (is_dir) +#ifdef VMS + { + extern int vms_report_unix_paths; + o = helper_return_file_len (o, vms_report_unix_paths ? "./" : "[]", + 2, style, is_last); + } +#else +# ifndef _AMIGA + o = helper_return_file_len (o, "./", 2, style, is_last); +# else + ; /* Just a nop... */ +# endif /* AMIGA */ +#endif /* !VMS */ + else + /* The entire name is the basename. */ + o = helper_return_file_len (o, path, end - path, style, is_last); + } + + free_ns_chain_no_strcache (chain); + return o; +} + +/* $(qnotdir style, path1 ... pathN) - same as $(notdir ), except for + files rather than word tokens. See func_notdir_suffix(). */ + +static char * +func_q_notdir (char *o, char **argv, const char *funcname) +{ + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT_VMS_TRICKS); + struct nameseq *chain = helper_parse_file_list (argv[1], style, 0); + struct nameseq *cur; + int const stop = MAP_DIRSEP; + (void)funcname; + + for (cur = chain; cur; cur = cur->next) + { + int const is_last = cur->next == NULL; + const char * const path = cur->name; + const char * const end = strchr(path, '\0'); + + /* Locate the last dot or path separator (P): */ + const char *p = path != end ? end - 1 : end; + while (p >= path && ! STOP_SET (*p, stop)) + --p; + + if ((uintptr_t)p >= (uintptr_t)path) + o = helper_return_file_len (o, p + 1, end - p - 1, style, is_last); +#ifdef HAVE_DOS_PATHS + else if (path[0] && path[1] == ':') /* "d:foo/bar" -> "foo/bar" */ + o = helper_return_file_len (o, path + 2, end - path - 2, style, is_last); +#endif + else + o = helper_return_file_len (o, path, end - path, style, is_last); + } + + free_ns_chain_no_strcache (chain); + return o; +} + +/* $(qsuffix style, path1 ... pathN) - same as $(suffix ), except for + files rather than word tokens. See func_notdir_suffix(). */ + +static char * +func_q_suffix (char *o, char **argv, const char *funcname) +{ + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT_VMS_TRICKS); + struct nameseq *chain = helper_parse_file_list (argv[1], style, 0); + struct nameseq *prev; + struct nameseq *cur; + int const stop = MAP_DIRSEP | MAP_DOT; + (void)funcname; + + /* For suffixes we do a pre-pass that removes elements without suffixes. + This simplifies the handling of end-quoting. */ + prev = NULL; + cur = chain; + while (cur) + { + const char * const path = cur->name; + if (strchr (path, '.') != NULL) + { + const char * const end = strchr (path, '\0'); + const char *p = end - 1; + while ((uintptr_t)p >= (uintptr_t)path && ! STOP_SET (*p, stop)) + --p; + if ((uintptr_t)p >= (uintptr_t)path && *p == '.') + { + if (p != path) + memmove ((char *)path, p, end - p + 1); + prev = cur; + cur = cur->next; + } + else /* remove it */ + cur = helper_unlink_and_free_ns (cur, prev, &chain); + } + else /* remove it */ + cur = helper_unlink_and_free_ns (cur, prev, &chain); + } + + /* Output pass: */ + return helper_return_and_free_chain (o, chain, style); +} + +# ifdef CONFIG_WITH_ROOT_FUNC +/* + $(qroot style, path...pathN) - same as $(root ), except files rather + than space delimited word tokens. See func_root(). + + This is mainly for dealing with drive letters and UNC paths on Windows + and OS/2. + */ +static char * +func_q_root (char *o, char **argv, const char *funcname UNUSED) +{ + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT); + struct nameseq *chain = helper_parse_file_list (argv[1], style, 0); + struct nameseq *prev; + struct nameseq *cur; + + /* First pass: Strip non-root components and remove rootless elements. */ + prev = NULL; + cur = chain; + while (cur) + { + const char *path = cur->name; + const char *end = NULL; + char ch; + +# ifdef HAVE_DOS_PATHS + if (isalpha(path[0]) && path[1] == ':') + end = path + 2; + else if ( IS_PATHSEP(path[0]) + && IS_PATHSEP(path[1]) + && !IS_PATHSEP(path[2]) && path[2] + && path[3]) + { + /* Min recognized UNC: "//./" - find the next slash + Typical root: "//srv/shr/" */ + /* XXX: Check if //./ needs special handling. */ + end = path + 3; + while ((ch = *end) != '\0' && !IS_PATHSEP(ch)) + end++; + + if (IS_PATHSEP(ch) && !IS_PATHSEP(end[1])) + { + end++; + while ((ch = *end) != '\0' && !IS_PATHSEP(ch)) + end++; + } + else + end = NULL; /* invalid */ + } + else if (IS_PATHSEP(*end)) + end = path + 1; + else + end = NULL; + +# elif defined (VMS) || defined (AMGIA) + /* XXX: VMS and AMGIA */ + OS (fatal, NILF, _("$(%s ) is not implemented on this platform"), funcname); +# else + if (IS_PATHSEP(*path)) + end = path + 1; +# endif + if (end != NULL) + { + /* Include all subsequent path separators. */ + + while ((ch = *end) != '\0' && IS_PATHSEP(ch)) + end++; + *(char *)end = '\0'; + + prev = cur; + cur = cur->next; + } + else + cur = helper_unlink_and_free_ns(cur, prev, &chain); + } + + /* Second pass: Output */ + return helper_return_and_free_chain (o, chain, style); +} + +/* + $(qnotroot style, path1 .. pathN) - same as $(notroot ), except files + rather than space delimited word tokens. See func_notroot(). + + This is mainly for dealing with drive letters and UNC paths on Windows + and OS/2. + */ +static char * +func_q_notroot (char *o, char **argv, const char *funcname UNUSED) +{ + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT); + struct nameseq *chain = helper_parse_file_list (argv[1], style, 0); + struct nameseq *cur; + + for (cur = chain; cur; cur = cur->next) + { + const char *start = cur->name; + char ch; + +# ifdef HAVE_DOS_PATHS + if (isalpha(start[0]) && start[1] == ':') + start += 2; + else if ( IS_PATHSEP(start[0]) + && IS_PATHSEP(start[1]) + && !IS_PATHSEP(start[2]) && start[2] != '\0' + && start[3] != '\0') + { + /* Min recognized UNC: "//./" - find the next slash + Typical root: "//srv/shr/" */ + /* XXX: Check if //./ needs special handling. */ + start += 3; + while ((ch = *start) != '\0' && !IS_PATHSEP(ch)) + start++; + + if (IS_PATHSEP(ch) && !IS_PATHSEP(start[1])) + { + start++; + while ((ch = *start) != '\0' && !IS_PATHSEP(ch)) + start++; + } + else + start = cur->name; /* invalid UNC, pretend it's a couple unixy root slashes. */ + } + +# elif defined (VMS) || defined (AMGIA) + /* XXX: VMS and AMGIA */ + OS (fatal, NILF, _("$(%s) is not implemented on this platform"), funcname); +# endif + + /* Exclude all subsequent / leading path separators. */ + while ((ch = *start) != '\0' && IS_PATHSEP(ch)) + start++; + + if (ch != '\0') + o = helper_return_file(o, start, style, cur->next == NULL); + else + o = helper_return_file_len (o, ".", 1, style, cur->next == NULL); + } + + free_ns_chain_no_strcache (chain); + return o; +} + +# endif + +/* $(qrealpath style, path1 .. pathN) - same as $(realpath ), except files + rather than space delimited word tokens. See func_realpath(). */ + +static char * +func_q_realpath (char *o, char **argv, const char *funcname UNUSED) +{ + PATH_VAR (outbuf); + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT); + struct nameseq *chain = helper_parse_file_list (argv[1], style, 0); + + /* Pass one: Do the realpath/abspath thing and remove anything that fails + or doesn't exists. */ + struct nameseq *cur = chain; + struct nameseq *prev = NULL; + while (cur) + { + char *result; +#ifdef HAVE_REALPATH + ENULLLOOP (result, realpath (cur->name, outbuf)); +#else + result = abspath (cur->name, outbuf); +#endif + if (result) + { + struct stat st; + int r; + EINTRLOOP (r, stat (outbuf, &st)); + if (r == 0) + { + free ((char *)cur->name); + cur->name = xstrdup (result); + prev = cur; + cur = cur->next; + } + else + cur = helper_unlink_and_free_ns(cur, prev, &chain); + } + else + cur = helper_unlink_and_free_ns(cur, prev, &chain); + } + + /* Pass two: Output. */ + return helper_return_and_free_chain (o, chain, style); +} + +/* $(qwildcard path1 .. pathN [, style]) - same as $(wildcard ), except files + rather than space delimited word tokens. See func_wildcard(). */ + +static char * +func_q_wildcard (char *o, char **argv, const char *funcname UNUSED) +{ + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT); + struct nameseq *chain = helper_parse_file_list (argv[1], style, 1 /*glob*/); +#ifdef _AMIGA + OS (fatal, NILF, _("$(%s ) is not implemented on this platform"), funcname); +#endif + return helper_return_and_free_chain (o, chain, style); +} + +static char * +worker_filter_filterout (char *o, char **argv, unsigned style, int is_filter) +{ + struct nameseq *wordchain; + struct a_word *wordhead; + struct a_word **wordtail; + struct a_word *wp; + struct nameseq *patchain; + struct a_pattern *pathead; + struct a_pattern **pattail; + struct a_pattern *pp; + struct nameseq *cur; + struct hash_table a_word_table; + int literals; + int words; + int hashing; + unsigned int words_len; /* for output estimation */ + + /* Chop ARGV[0] up into patterns to match against the words. */ + /** @todo this very inefficient as we convert between two list format and + * duplicates the patterns on the heap. We could just modify argv[0] + * directly. */ + patchain = helper_parse_file_list (argv[0], style, 0 /*glob*/); + pattail = &pathead; + for (cur = patchain, literals = 0; cur; cur = cur->next) + { + struct a_pattern *pat = alloca (sizeof (struct a_pattern)); + + *pattail = pat; + pattail = &pat->next; + + pat->str = (char *)cur->name; /* (safe - PARSEFS_NOCACHE) */ + pat->percent = find_percent (pat->str); /* may modify name */ + if (pat->percent == 0) + literals++; + pat->sfxlen = pat->percent ? strlen(pat->percent + 1) : 0; + pat->length = strlen (pat->str); + } + *pattail = NULL; + + /* Chop ARGV[1] up into words to match against the patterns. */ + /** @todo this very inefficient as we convert between two list format and + * duplicates the words on the heap. We could just modify argv[1] + * directly. */ + wordchain = helper_parse_file_list (argv[1], style, 0 /*glob*/); + wordtail = &wordhead; + for (cur = wordchain, words = 0, words_len = 0; cur; cur = cur->next) + { + struct a_word *word = alloca (sizeof (struct a_word)); + + *wordtail = word; + wordtail = &word->next; + + word->str = (char *)cur->name; /* (safe - PARSEFS_NOCACHE) */ + word->length = strlen (cur->name); + words_len += word->length + 1; + word->matched = 0; + word->chain = NULL; + words++; + } + *wordtail = NULL; + + /* Only use a hash table if arg list lengths justifies the cost. */ + hashing = (literals >= 2 && (literals * words) >= 10); + if (hashing) + { + hash_init (&a_word_table, words, a_word_hash_1, a_word_hash_2, + a_word_hash_cmp); + for (wp = wordhead; wp != 0; wp = wp->next) + { + struct a_word *owp = hash_insert (&a_word_table, wp); + if (owp) + wp->chain = owp; + } + } + + if (words) + { + int doneany = 0; + + if (is_filter) + words_len = 0; + + /* Run each pattern through the words, killing words. */ + for (pp = pathead; pp != 0; pp = pp->next) + { + if (pp->percent) + { + for (wp = wordhead; wp != 0; wp = wp->next) + if (!wp->matched + && pattern_matches_ex (pp->str, pp->percent, pp->sfxlen, + wp->str, wp->length)) + { + wp->matched = 1; + if (is_filter) + words_len += wp->length + 1; + else + words_len -= wp->length + 1; + } + } + else if (hashing) + { + struct a_word a_word_key; + a_word_key.str = pp->str; + a_word_key.length = pp->length; + wp = hash_find_item (&a_word_table, &a_word_key); + while (wp) + { + if (!wp->matched) + { + wp->matched = 1; + if (is_filter) + words_len += wp->length + 1; + else + words_len -= wp->length + 1; + } + wp = wp->chain; + } + } + else + for (wp = wordhead; wp != 0; wp = wp->next) + if (!wp->matched + && wp->length == pp->length + && strneq (pp->str, wp->str, wp->length)) + { + wp->matched = 1; + if (is_filter) + words_len += wp->length + 1; + else + words_len -= wp->length + 1; + } + } + + /* Output the words that matched (or didn't, for filter-out). */ + o = ensure_variable_buffer_space (o, words_len); + + for (wp = wordhead; wp != 0; wp = wp->next) + if (wp->matched == is_filter) + { + o = helper_return_file_len (o, wp->str, wp->length, + style, 0 /*is_last*/); + doneany = 1; + } + + /* Kill the last separator. */ + if (doneany) + o = helper_drop_separator (o, style); + } + + /* Clean up. */ + if (hashing) + hash_free (&a_word_table, 0); + free_ns_chain_no_strcache (wordchain); + free_ns_chain_no_strcache (patchain); + + return o; +} + +/* Implements $(qfilter ) and $(qfilter-out ). */ +static char * +func_q_filter_filterout (char *o, char **argv, const char *funcname) +{ + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT); + return worker_filter_filterout (o, &argv[1], style, funcname[7] == '\0'); +} + +#endif /* KMK */ + +#ifdef CONFIG_WITH_LAZY_DEPS_VARS + +/* Helper that parses the index argument for the $(deps* ) and $(qdeps* ) + functions. */ +static unsigned int parse_dep_index (const char *index, const char *funcname) +{ + unsigned int idx = 0; + if (index) + { + while (ISSPACE (*index)) + index++; + if (*index != '\0') + { + char *next = (char *)index; + long l = strtol (index, &next, 0); + while (ISSPACE (*next)) + next++; + idx = (unsigned int)l; + if (*next != '\0' || l < 0 || (long)idx != l) + OSS (fatal, NILF, _("%s: invalid index value: `%s'\n"), funcname, index); + } + } + return idx; +} + +/* Helper that calculates the output length for a dependency */ + +MY_INLINE unsigned int helper_dep_output_len (struct dep *d) +{ + const char *c = dep_name (d); +#ifndef NO_ARCHIVES + if (ar_name (c)) + return strlen (strchr (c, '(') + 1); +#endif +#ifdef CONFIG_WITH_STRCACHE2 + if (!d->need_2nd_expansion) + return strcache2_get_len (&file_strcache, c) + 1; +#endif + return strlen (c) + 1; +} + +/* Helper that outputs a depndency. */ + +MY_INLINE char *helper_dep_output_one (char *o, struct dep *d, + unsigned int style, int is_last) +{ + const char *c = dep_name (d); +#ifndef NO_ARCHIVES + if (ar_name (c)) + { + c = strchr(c, '(') + 1; + o = helper_return_file_len (o, c, strlen(c) - 1, style, is_last); + } + else +#endif +#ifdef CONFIG_WITH_STRCACHE2 + if (!d->need_2nd_expansion) + { + unsigned int len = strcache2_get_len (&file_strcache, c); + o = helper_return_file_len (o, c, len, style, is_last); + } + else +#endif + o = helper_return_file (o, c, style, is_last); + return o; +} + +/* Implements $^/$(deps )/$(qdeps ) and $+/$(deps-all )/$(qdeps-all ). + + If no second argument is given, or if it's empty, or if it's zero, + all dependencies will be returned. If the second argument is non-zero + the dependency at that position will be returned. If the argument is + negative a fatal error is thrown. */ +static char * +worker_deps (char *o, char **argv, const char *funcname, unsigned int style, + int all_deps) +{ + unsigned int idx = parse_dep_index (argv[1], funcname); + struct file *file; + + /* Find the file and select the list corresponding to FUNCNAME. */ + + file = lookup_file (argv[0]); + if (file) + { + struct dep *deps; + struct dep *d; + if (!all_deps) + { + deps = file->deps_no_dupes; + if (!deps && file->deps) + deps = file->deps_no_dupes = create_uniqute_deps_chain (file->deps); + } + else + deps = file->deps; + + if ( file->double_colon + && ( file->double_colon != file + || file->last != file)) + OSS (error, NILF, _("$(%s ) cannot be used on files with multiple double colon rules like `%s'\n"), + funcname, file->name); + + if (idx == 0 /* all */) + { + /* Since this may be a long list, calculate the output space needed if + no quoting takes place and no multichar separators are used. */ + + unsigned int total_len = 0; + for (d = deps; d; d = d->next) + if (!d->ignore_mtime) + total_len += helper_dep_output_len (d); + if (total_len > 0) + { + o = ensure_variable_buffer_space (o, total_len); + + for (d = deps; d; d = d->next) + if (!d->ignore_mtime) + o = helper_dep_output_one (o, d, style, 0 /*is_last*/); + + /* nuke the last list separator */ + o = helper_drop_separator (o, style); + } + } + else + { + /* Dependency given by index. */ + + for (d = deps; d; d = d->next) + if (!d->ignore_mtime) + if (--idx == 0) /* 1 based indexing */ + return helper_dep_output_one (o, d, style, 1 /*is_last*/); + } + } + + return o; +} + +/* Implements $? / $(deps-newer ) / $(qdeps-newer ). + + If no second argument is given, or if it's empty, or if it's zero, + all dependencies will be returned. If the second argument is non-zero + the dependency at that position will be returned. If the argument is + negative a fatal error is thrown. */ +static char * +worker_deps_newer (char *o, char **argv, const char *funcname, unsigned int style) +{ + unsigned int idx = parse_dep_index (argv[1], funcname); + struct file *file; + + /* Find the file. */ + + file = lookup_file (argv[0]); + if (file) + { + struct dep *deps = file->deps; + struct dep *d; + + if ( file->double_colon + && ( file->double_colon != file + || file->last != file)) + OSS (error, NILF, _("$(%s ) cannot be used on files with multiple double colon rules like `%s'\n"), + funcname, file->name); + + if (idx == 0 /* all */) + { + unsigned int total_len = 0; + + /* calc the result length. */ + + for (d = deps; d; d = d->next) + if (!d->ignore_mtime && d->changed) + total_len += helper_dep_output_len (d); + if (total_len) + { + o = ensure_variable_buffer_space (o, total_len); + + for (d = deps; d; d = d->next) + if (!d->ignore_mtime && d->changed) + o = helper_dep_output_one (o, d, style, 0 /*is_last*/); + + /* nuke the last list separator */ + o = helper_drop_separator (o, style); + } + } + else + { + /* Dependency given by index. */ + + for (d = deps; d; d = d->next) + if (!d->ignore_mtime && d->changed) + if (--idx == 0) /* 1 based indexing */ + return helper_dep_output_one (o, d, style, 1 /*is_last*/); + } + } + + return o; +} + +/* Implements $|, the order only dependency list. + + If no second argument is given, or if it's empty, or if it's zero, + all dependencies will be returned. If the second argument is non-zero + the dependency at that position will be returned. If the argument is + negative a fatal error is thrown. */ +static char * +worker_deps_order_only (char *o, char **argv, const char *funcname, unsigned int style) +{ + unsigned int idx = parse_dep_index (argv[1], funcname); + struct file *file; + + /* Find the file. */ + + file = lookup_file (argv[0]); + if (file) + { + struct dep *deps = file->deps; + struct dep *d; + + if ( file->double_colon + && ( file->double_colon != file + || file->last != file)) + OSS (error, NILF, _("$(%s ) cannot be used on files with multiple double colon rules like `%s'\n"), + funcname, file->name); + + if (idx == 0 /* all */) + { + unsigned int total_len = 0; + + /* calc the result length. */ + + for (d = deps; d; d = d->next) + if (d->ignore_mtime) + total_len += helper_dep_output_len (d); + if (total_len) + { + o = ensure_variable_buffer_space (o, total_len); + + for (d = deps; d; d = d->next) + if (d->ignore_mtime) + o = helper_dep_output_one (o, d, style, 0 /*is_last*/); + + /* nuke the last list separator */ + o = helper_drop_separator (o, style); + } + } + else + { + /* Dependency given by index. */ + + for (d = deps; d; d = d->next) + if (d->ignore_mtime) + if (--idx == 0) /* 1 based indexing */ + return helper_dep_output_one (o, d, style, 1 /*is_last*/); + } + } + + return o; +} + +/* Implements $^ and $+. + + The first comes with FUNCNAME 'deps', the second as 'deps-all'. + + If no second argument is given, or if it's empty, or if it's zero, + all dependencies will be returned. If the second argument is non-zero + the dependency at that position will be returned. If the argument is + negative a fatal error is thrown. */ +static char * +func_deps (char *o, char **argv, const char *funcname) +{ +# ifdef VMS + return worker_deps (o, argv, funcname, Q_RET_UNQUOTED | Q_SEP_COMMA, +# else + return worker_deps (o, argv, funcname, Q_RET_UNQUOTED | Q_SEP_SPACE, +# endif + funcname[4] != '\0'); +} + +/* Implements $?. + + If no second argument is given, or if it's empty, or if it's zero, + all dependencies will be returned. If the second argument is non-zero + the dependency at that position will be returned. If the argument is + negative a fatal error is thrown. */ +static char * +func_deps_newer (char *o, char **argv, const char *funcname) +{ +# ifdef VMS + return worker_deps_newer (o, argv, funcname, Q_RET_UNQUOTED | Q_SEP_COMMA); +# else + return worker_deps_newer (o, argv, funcname, Q_RET_UNQUOTED | Q_SEP_SPACE); +# endif +} + +/* Implements $|, the order only dependency list. + + If no second argument is given, or if it's empty, or if it's zero, + all dependencies will be returned. If the second argument is non-zero + the dependency at that position will be returned. If the argument is + negative a fatal error is thrown. */ +static char * +func_deps_order_only (char *o, char **argv, const char *funcname) +{ +# ifdef VMS + return worker_deps_order_only (o, argv, funcname, Q_RET_UNQUOTED | Q_SEP_COMMA); +# else + return worker_deps_order_only (o, argv, funcname, Q_RET_UNQUOTED | Q_SEP_SPACE); +# endif +} + +#endif /* CONFIG_WITH_LAZY_DEPS_VARS */ +#ifdef KMK + +/* Implements $(qdeps ) and $(qdeps-all ) + + If no third argument is given, or if it's empty, or if it's zero, + all dependencies will be returned. If the third argument is non-zero + the dependency at that position will be returned. If the argument is + negative a fatal error is thrown. */ +static char * +func_q_deps (char *o, char **argv, const char *funcname) +{ + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT); + return worker_deps (o, &argv[1], funcname, style, funcname[5] != '\0'); +} + +/* Implements $(qdeps-newer ). + + If no third argument is given, or if it's empty, or if it's zero, + all dependencies will be returned. If the third argument is non-zero + the dependency at that position will be returned. If the argument is + negative a fatal error is thrown. */ +static char * +func_q_deps_newer (char *o, char **argv, const char *funcname) +{ + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT); + return worker_deps_newer (o, &argv[1], funcname, style); +} + +/* Implements $(qdeps-oo ), the order only dependency list. + + If no third argument is given, or if it's empty, or if it's zero, + all dependencies will be returned. If the third argument is non-zero + the dependency at that position will be returned. If the argument is + negative a fatal error is thrown. */ +static char * +func_q_deps_order_only (char *o, char **argv, const char *funcname) +{ + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT); + return worker_deps_order_only (o, &argv[1], funcname, style); +} + +/* Implements $(qtarget ), converting a single unquoted file to the given + quoting style. + + Typically used like this: + $(qtarget sh,$@) + $(qone-unquoted sh,$@) */ +static char * +func_q_one_unquoted (char *o, char **argv, const char *funcname) +{ + unsigned int const style = helper_file_quoting_style (argv[0], Q_QDEFAULT); + return helper_return_file (o, argv[1], style, 1 /*is_last*/); +} + +#endif /* KMK */ + +/* Lookup table for builtin functions. + + This doesn't have to be sorted; we use a straight lookup. We might gain + some efficiency by moving most often used functions to the start of the + table. + + If MAXIMUM_ARGS is 0, that means there is no maximum and all + comma-separated values are treated as arguments. + + EXPAND_ARGS means that all arguments should be expanded before invocation. + Functions that do namespace tricks (foreach) don't automatically expand. */ + +static char *func_call (char *o, char **argv, const char *funcname); + +#define FT_ENTRY(_name, _min, _max, _exp, _func) \ + { { (_func) }, STRING_SIZE_TUPLE(_name), (_min), (_max), (_exp), 0 } + +static struct function_table_entry function_table_init[] = +{ + /* Name MIN MAX EXP? Function */ + FT_ENTRY ("abspath", 0, 1, 1, func_abspath), + FT_ENTRY ("addprefix", 2, 2, 1, func_addsuffix_addprefix), + FT_ENTRY ("addsuffix", 2, 2, 1, func_addsuffix_addprefix), + FT_ENTRY ("basename", 0, 1, 1, func_basename_dir), + FT_ENTRY ("dir", 0, 1, 1, func_basename_dir), + FT_ENTRY ("notdir", 0, 1, 1, func_notdir_suffix), +#ifdef CONFIG_WITH_ROOT_FUNC + FT_ENTRY ("root", 0, 1, 1, func_root), + FT_ENTRY ("notroot", 0, 1, 1, func_notroot), +#endif + FT_ENTRY ("subst", 3, 3, 1, func_subst), + FT_ENTRY ("suffix", 0, 1, 1, func_notdir_suffix), + FT_ENTRY ("filter", 2, 2, 1, func_filter_filterout), + FT_ENTRY ("filter-out", 2, 2, 1, func_filter_filterout), + FT_ENTRY ("findstring", 2, 2, 1, func_findstring), +#ifdef CONFIG_WITH_DEFINED_FUNCTIONS + FT_ENTRY ("firstdefined", 0, 2, 1, func_firstdefined), +#endif + FT_ENTRY ("firstword", 0, 1, 1, func_firstword), + FT_ENTRY ("flavor", 0, 1, 1, func_flavor), + FT_ENTRY ("join", 2, 2, 1, func_join), +#ifdef CONFIG_WITH_DEFINED_FUNCTIONS + FT_ENTRY ("lastdefined", 0, 2, 1, func_lastdefined), +#endif + FT_ENTRY ("lastword", 0, 1, 1, func_lastword), + FT_ENTRY ("patsubst", 3, 3, 1, func_patsubst), + FT_ENTRY ("realpath", 0, 1, 1, func_realpath), +#ifdef CONFIG_WITH_RSORT + FT_ENTRY ("rsort", 0, 1, 1, func_sort), +# ifdef KMK + FT_ENTRY ("rversort", 0, 1, 1, func_sort), +# endif +#endif + FT_ENTRY ("shell", 0, 1, 1, func_shell), + FT_ENTRY ("sort", 0, 1, 1, func_sort), +# ifdef KMK + FT_ENTRY ("versort", 0, 1, 1, func_sort), +# endif + FT_ENTRY ("strip", 0, 1, 1, func_strip), +#ifdef CONFIG_WITH_WHERE_FUNCTION + FT_ENTRY ("where", 0, 1, 1, func_where), +#endif + FT_ENTRY ("wildcard", 0, 1, 1, func_wildcard), + FT_ENTRY ("word", 2, 2, 1, func_word), + FT_ENTRY ("wordlist", 3, 3, 1, func_wordlist), + FT_ENTRY ("words", 0, 1, 1, func_words), + FT_ENTRY ("origin", 0, 1, 1, func_origin), + FT_ENTRY ("foreach", 3, 3, 0, func_foreach), +#ifdef CONFIG_WITH_LOOP_FUNCTIONS + FT_ENTRY ("for", 4, 4, 0, func_for), + FT_ENTRY ("while", 2, 2, 0, func_while), +#endif + FT_ENTRY ("call", 1, 0, 1, func_call), + FT_ENTRY ("info", 0, 1, 1, func_error), + FT_ENTRY ("error", 0, 1, 1, func_error), + FT_ENTRY ("warning", 0, 1, 1, func_error), + FT_ENTRY ("if", 2, 3, 0, func_if), + FT_ENTRY ("or", 1, 0, 0, func_or), + FT_ENTRY ("and", 1, 0, 0, func_and), + FT_ENTRY ("value", 0, 1, 1, func_value), +#ifdef EXPERIMENTAL + FT_ENTRY ("eq", 2, 2, 1, func_eq), + FT_ENTRY ("not", 0, 1, 1, func_not), +#endif + FT_ENTRY ("eval", 0, 1, 1, func_eval), +#ifdef CONFIG_WITH_EVALPLUS + FT_ENTRY ("evalctx", 0, 1, 1, func_evalctx), + FT_ENTRY ("evalval", 1, 1, 1, func_evalval), + FT_ENTRY ("evalvalctx", 1, 1, 1, func_evalval), + FT_ENTRY ("evalcall", 1, 0, 1, func_call), + FT_ENTRY ("evalcall2", 1, 0, 1, func_call), + FT_ENTRY ("eval-opt-var", 1, 0, 1, func_eval_optimize_variable), +#endif + FT_ENTRY ("file", 1, 2, 1, func_file), +#ifdef CONFIG_WITH_STRING_FUNCTIONS + FT_ENTRY ("length", 1, 1, 1, func_length), + FT_ENTRY ("length-var", 1, 1, 1, func_length_var), + FT_ENTRY ("insert", 2, 5, 1, func_insert), + FT_ENTRY ("pos", 2, 3, 1, func_pos), + FT_ENTRY ("lastpos", 2, 3, 1, func_pos), + FT_ENTRY ("substr", 2, 4, 1, func_substr), + FT_ENTRY ("translate", 2, 4, 1, func_translate), +#endif +#ifdef CONFIG_WITH_PRINTF + FT_ENTRY ("printf", 1, 0, 1, kmk_builtin_func_printf), +#endif +#ifdef CONFIG_WITH_LAZY_DEPS_VARS + FT_ENTRY ("deps", 1, 2, 1, func_deps), + FT_ENTRY ("deps-all", 1, 2, 1, func_deps), + FT_ENTRY ("deps-newer", 1, 2, 1, func_deps_newer), + FT_ENTRY ("deps-oo", 1, 2, 1, func_deps_order_only), +#endif +#ifdef CONFIG_WITH_DEFINED + FT_ENTRY ("defined", 1, 1, 1, func_defined), +#endif +#ifdef CONFIG_WITH_TOUPPER_TOLOWER + FT_ENTRY ("toupper", 0, 1, 1, func_toupper_tolower), + FT_ENTRY ("tolower", 0, 1, 1, func_toupper_tolower), +#endif +#ifdef CONFIG_WITH_ABSPATHEX + FT_ENTRY ("abspathex", 0, 2, 1, func_abspathex), +#endif +#ifdef CONFIG_WITH_XARGS + FT_ENTRY ("xargs", 2, 0, 1, func_xargs), +#endif +#if defined(CONFIG_WITH_VALUE_LENGTH) && defined(CONFIG_WITH_COMPARE) + FT_ENTRY ("comp-vars", 3, 3, 1, func_comp_vars), + FT_ENTRY ("comp-cmds", 3, 3, 1, func_comp_vars), + FT_ENTRY ("comp-cmds-ex", 3, 3, 1, func_comp_cmds_ex), +#endif +#ifdef CONFIG_WITH_DATE + FT_ENTRY ("date", 0, 1, 1, func_date), + FT_ENTRY ("date-utc", 0, 3, 1, func_date), +#endif +#ifdef CONFIG_WITH_FILE_SIZE + FT_ENTRY ("file-size", 1, 1, 1, func_file_size), +#endif +#ifdef CONFIG_WITH_WHICH + FT_ENTRY ("which", 0, 0, 1, func_which), +#endif +#ifdef CONFIG_WITH_IF_CONDITIONALS + FT_ENTRY ("expr", 1, 1, 0, func_expr), + FT_ENTRY ("if-expr", 2, 3, 0, func_if_expr), + FT_ENTRY ("select", 2, 0, 0, func_select), +#endif +#ifdef CONFIG_WITH_SET_CONDITIONALS + FT_ENTRY ("intersects", 2, 2, 1, func_set_intersects), +#endif +#ifdef CONFIG_WITH_STACK + FT_ENTRY ("stack-push", 2, 2, 1, func_stack_push), + FT_ENTRY ("stack-pop", 1, 1, 1, func_stack_pop_top), + FT_ENTRY ("stack-popv", 1, 1, 1, func_stack_pop_top), + FT_ENTRY ("stack-top", 1, 1, 1, func_stack_pop_top), +#endif +#ifdef CONFIG_WITH_MATH + FT_ENTRY ("int-add", 2, 0, 1, func_int_add), + FT_ENTRY ("int-sub", 2, 0, 1, func_int_sub), + FT_ENTRY ("int-mul", 2, 0, 1, func_int_mul), + FT_ENTRY ("int-div", 2, 0, 1, func_int_div), + FT_ENTRY ("int-mod", 2, 2, 1, func_int_mod), + FT_ENTRY ("int-not", 1, 1, 1, func_int_not), + FT_ENTRY ("int-and", 2, 0, 1, func_int_and), + FT_ENTRY ("int-or", 2, 0, 1, func_int_or), + FT_ENTRY ("int-xor", 2, 0, 1, func_int_xor), + FT_ENTRY ("int-eq", 2, 2, 1, func_int_cmp), + FT_ENTRY ("int-ne", 2, 2, 1, func_int_cmp), + FT_ENTRY ("int-gt", 2, 2, 1, func_int_cmp), + FT_ENTRY ("int-ge", 2, 2, 1, func_int_cmp), + FT_ENTRY ("int-lt", 2, 2, 1, func_int_cmp), + FT_ENTRY ("int-le", 2, 2, 1, func_int_cmp), +#endif +#ifdef CONFIG_WITH_NANOTS + FT_ENTRY ("nanots", 0, 0, 0, func_nanots), +#endif +#ifdef CONFIG_WITH_OS2_LIBPATH + FT_ENTRY ("libpath", 1, 2, 1, func_os2_libpath), +#endif +#if defined (CONFIG_WITH_MAKE_STATS) || defined (CONFIG_WITH_MINIMAL_STATS) + FT_ENTRY ("make-stats", 0, 0, 0, func_make_stats), +#endif +#ifdef CONFIG_WITH_COMMANDS_FUNC + FT_ENTRY ("commands", 1, 1, 1, func_commands), + FT_ENTRY ("commands-sc", 1, 1, 1, func_commands), + FT_ENTRY ("commands-usr", 2, 2, 1, func_commands), +#endif +#ifdef KMK_HELPERS + FT_ENTRY ("kb-src-tool", 1, 2, 0, func_kbuild_source_tool), + FT_ENTRY ("kb-obj-base", 1, 2, 0, func_kbuild_object_base), + FT_ENTRY ("kb-obj-suff", 1, 2, 0, func_kbuild_object_suffix), + FT_ENTRY ("kb-src-prop", 3, 4, 0, func_kbuild_source_prop), + FT_ENTRY ("kb-src-one", 0, 1, 0, func_kbuild_source_one), + FT_ENTRY ("kb-exp-tmpl", 6, 6, 1, func_kbuild_expand_template), +#endif +#ifdef KMK + FT_ENTRY ("dircache-ctl", 1, 0, 1, func_dircache_ctl), + FT_ENTRY ("breakpoint", 0, 0, 0, func_breakpoint), + FT_ENTRY ("set-umask", 1, 3, 1, func_set_umask), + FT_ENTRY ("get-umask", 0, 0, 0, func_get_umask), +#endif +#ifdef KMK + FT_ENTRY ("quote", 1, 0, 1, func_quote_make), + FT_ENTRY ("quote-dep", 1, 0, 1, func_quote_make), + FT_ENTRY ("quote-tgt", 1, 0, 1, func_quote_make), + FT_ENTRY ("quote-depend", 1, 0, 1, func_quote_make), + FT_ENTRY ("quote-tgtend", 1, 0, 1, func_quote_make), + FT_ENTRY ("quote-sh", 1, 0, 1, func_quote_shell), + FT_ENTRY ("quote-sh-dq", 1, 1, 1, func_quote_shell_dq), + FT_ENTRY ("quote-sh-sq", 1, 1, 1, func_quote_shell_sq), + FT_ENTRY ("requote", 1, 0, 1, func_requote), + /* Quoted input and maybe output variants of functions typically + working with files: */ + FT_ENTRY ("firstfile", 0, 1, 1, func_firstfile), + FT_ENTRY ("lastfile", 0, 1, 1, func_lastfile), + FT_ENTRY ("filelist", 3, 3, 1, func_filelist), + FT_ENTRY ("countfiles", 0, 1, 1, func_countfiles), + FT_ENTRY ("foreachfile", 3, 3, 0, func_foreachfile), + FT_ENTRY ("sortfiles", 0, 1, 1, func_sortfiles), + FT_ENTRY ("versortfiles", 0, 1, 1, func_sortfiles), +# ifdef CONFIG_WITH_RSORT + FT_ENTRY ("rsortfiles", 0, 1, 1, func_sortfiles), + FT_ENTRY ("rversortfiles", 0, 1, 1, func_sortfiles), +# endif + /* Function variants with preceding style argument and quoting by default. */ + FT_ENTRY ("qfirstfile", 1+0, 1+1, 1, func_q_firstfile), + FT_ENTRY ("qlastfile", 1+0, 1+1, 1, func_q_lastfile), + FT_ENTRY ("qfilelist", 1+3, 1+3, 1, func_q_filelist), + FT_ENTRY ("qcountfiles", 1+0, 1+1, 1, func_q_countfiles), + FT_ENTRY ("qforeachfile", 1+3, 1+3, 0, func_q_foreachfile), + FT_ENTRY ("qsortfiles", 1+0, 1+1, 1, func_q_sortfiles), + FT_ENTRY ("qversortfiles",1+0, 1+1, 1, func_q_sortfiles), +# ifdef CONFIG_WITH_RSORT + FT_ENTRY ("qrsortfiles", 1+0, 1+1, 1, func_q_sortfiles), + FT_ENTRY ("qrversortfiles",1+0,1+1, 1, func_q_sortfiles), +# endif + FT_ENTRY ("qabspath", 1+0, 1+1, 1, func_q_abspath), + FT_ENTRY ("qaddprefix", 1+2, 1+2, 1, func_q_addsuffix_addprefix), + FT_ENTRY ("qaddsuffix", 1+2, 1+2, 1, func_q_addsuffix_addprefix), + FT_ENTRY ("qbasename", 1+0, 1+1, 1, func_q_basename_dir), + FT_ENTRY ("qdir", 1+0, 1+1, 1, func_q_basename_dir), + FT_ENTRY ("qnotdir", 1+0, 1+1, 1, func_q_notdir), +# ifdef CONFIG_WITH_ROOT_FUNC + FT_ENTRY ("qroot", 1+0, 1+1, 1, func_q_root), + FT_ENTRY ("qnotroot", 1+0, 1+1, 1, func_q_notroot), +# endif + FT_ENTRY ("qsuffix", 1+0, 1+1, 1, func_q_suffix), + FT_ENTRY ("qrealpath", 1+0, 1+1, 1, func_q_realpath), +# ifdef CONFIG_WITH_ABSPATHEX + FT_ENTRY ("qabspathex", 1+0, 1+2, 1, func_q_abspathex), +# endif + FT_ENTRY ("qwildcard", 1+0, 1+1, 1, func_q_wildcard), + FT_ENTRY ("qone-unquoted",1+1, 1+1, 1, func_q_one_unquoted), + FT_ENTRY ("qtarget", 1+1, 1+1, 1, func_q_one_unquoted), /* For requoting plain $@ to given style. */ + FT_ENTRY ("qdeps", 1+1, 1+2, 1, func_q_deps), /* $^ with quoting style */ + FT_ENTRY ("qdeps-all", 1+1, 1+2, 1, func_q_deps), /* $+ with quoting style */ + FT_ENTRY ("qdeps-newer", 1+1, 1+2, 1, func_q_deps_newer), /* $? with quoting style */ + FT_ENTRY ("qdeps-oo", 1+1, 1+2, 1, func_q_deps_order_only), /* $| with quoting style */ + FT_ENTRY ("qfilter", 1+2, 1+2, 1, func_q_filter_filterout), + FT_ENTRY ("qfilter-out", 1+2, 1+2, 1, func_q_filter_filterout), + /** @todo XXX: Add more qxxxx variants. */ +#endif +}; + +#define FUNCTION_TABLE_ENTRIES (sizeof (function_table_init) / sizeof (struct function_table_entry)) + + +/* These must come after the definition of function_table. */ + +static char * +expand_builtin_function (char *o, int argc, char **argv, + const struct function_table_entry *entry_p) +{ + char *p; + + if (argc < (int)entry_p->minimum_args) + fatal (*expanding_var, strlen (entry_p->name), + _("insufficient number of arguments (%d) to function '%s'"), + argc, entry_p->name); + + /* I suppose technically some function could do something with no arguments, + but so far no internal ones do, so just test it for all functions here + rather than in each one. We can change it later if necessary. */ + + if (!argc && !entry_p->alloc_fn) + return o; + + if (!entry_p->fptr.func_ptr) + OS (fatal, *expanding_var, + _("unimplemented on this platform: function '%s'"), entry_p->name); + + if (!entry_p->alloc_fn) + return entry_p->fptr.func_ptr (o, argv, entry_p->name); + + /* This function allocates memory and returns it to us. + Write it to the variable buffer, then free it. */ + + p = entry_p->fptr.alloc_func_ptr (entry_p->name, argc, argv); + if (p) + { + o = variable_buffer_output (o, p, strlen (p)); + free (p); + } + + return o; +} + +/* Check for a function invocation in *STRINGP. *STRINGP points at the + opening ( or { and is not null-terminated. If a function invocation + is found, expand it into the buffer at *OP, updating *OP, incrementing + *STRINGP past the reference and returning nonzero. If not, return zero. */ + +static int +handle_function2 (const struct function_table_entry *entry_p, char **op, const char **stringp) /* bird split it up. */ +{ + char openparen = (*stringp)[0]; + char closeparen = openparen == '(' ? ')' : '}'; + const char *beg; + const char *end; + int count = 0; + char *abeg = NULL; + char **argv, **argvp; + int nargs; + + beg = *stringp + 1; + + /* We found a builtin function. Find the beginning of its arguments (skip + whitespace after the name). */ + + beg += entry_p->len; + NEXT_TOKEN (beg); + + /* Find the end of the function invocation, counting nested use of + whichever kind of parens we use. Since we're looking, count commas + to get a rough estimate of how many arguments we might have. The + count might be high, but it'll never be low. */ + + for (nargs=1, end=beg; *end != '\0'; ++end) + if (*end == ',') + ++nargs; + else if (*end == openparen) + ++count; + else if (*end == closeparen && --count < 0) + break; + + if (count >= 0) + fatal (*expanding_var, strlen (entry_p->name), + _("unterminated call to function '%s': missing '%c'"), + entry_p->name, closeparen); + + *stringp = end; + + /* Get some memory to store the arg pointers. */ + argvp = argv = alloca (sizeof (char *) * (nargs + 2)); + + /* Chop the string into arguments, then a nul. As soon as we hit + MAXIMUM_ARGS (if it's >0) assume the rest of the string is part of the + last argument. + + If we're expanding, store pointers to the expansion of each one. If + not, make a duplicate of the string and point into that, nul-terminating + each argument. */ + + if (entry_p->expand_args) + { + const char *p; + for (p=beg, nargs=0; p <= end; ++argvp) + { + const char *next; + + ++nargs; + + if (nargs == entry_p->maximum_args + || (! (next = find_next_argument (openparen, closeparen, p, end)))) + next = end; + + *argvp = expand_argument (p, next); + p = next + 1; + } + } + else + { + int len = end - beg; + char *p, *aend; + + abeg = xmalloc (len+1); + memcpy (abeg, beg, len); + abeg[len] = '\0'; + aend = abeg + len; + + for (p=abeg, nargs=0; p <= aend; ++argvp) + { + char *next; + + ++nargs; + + if (nargs == entry_p->maximum_args + || (! (next = find_next_argument (openparen, closeparen, p, aend)))) + next = aend; + + *argvp = p; + *next = '\0'; + p = next + 1; + } + } + *argvp = NULL; + + /* Finally! Run the function... */ + *op = expand_builtin_function (*op, nargs, argv, entry_p); + + /* Free memory. */ + if (entry_p->expand_args) + for (argvp=argv; *argvp != 0; ++argvp) + free (*argvp); + else + free (abeg); + + return 1; +} + + +int /* bird split it up and hacked it. */ +#ifndef CONFIG_WITH_VALUE_LENGTH +handle_function (char **op, const char **stringp) +{ + const struct function_table_entry *entry_p = lookup_function (*stringp + 1); + if (!entry_p) + return 0; + return handle_function2 (entry_p, op, stringp); +} +#else /* CONFIG_WITH_VALUE_LENGTH */ +handle_function (char **op, const char **stringp, const char *nameend, const char *eol UNUSED) +{ + const char *fname = *stringp + 1; + const struct function_table_entry *entry_p = + lookup_function_in_hash_tab (fname, nameend - fname); + if (!entry_p) + return 0; + return handle_function2 (entry_p, op, stringp); +} +#endif /* CONFIG_WITH_VALUE_LENGTH */ + +#ifdef CONFIG_WITH_COMPILER +/* Used by the "compiler" to get all info about potential functions. */ +make_function_ptr_t +lookup_function_for_compiler (const char *name, unsigned int len, + unsigned char *minargsp, unsigned char *maxargsp, + char *expargsp, const char **funcnamep) +{ + const struct function_table_entry *entry_p = lookup_function (name, len); + if (!entry_p) + return 0; + *minargsp = entry_p->minimum_args; + *maxargsp = entry_p->maximum_args; + *expargsp = entry_p->expand_args; + *funcnamep = entry_p->name; + return entry_p->func_ptr; +} +#endif /* CONFIG_WITH_COMPILER */ + + +/* User-defined functions. Expand the first argument as either a builtin + function or a make variable, in the context of the rest of the arguments + assigned to $1, $2, ... $N. $0 is the name of the function. */ + +static char * +func_call (char *o, char **argv, const char *funcname UNUSED) +{ + static int max_args = 0; + char *fname; + char *body; + int flen; + int i; + int saved_args; + const struct function_table_entry *entry_p; + struct variable *v; +#ifdef CONFIG_WITH_EVALPLUS + char *buf; + unsigned int len; +#endif +#ifdef CONFIG_WITH_VALUE_LENGTH + char *fname_end; +#endif +#if defined (CONFIG_WITH_EVALPLUS) || defined (CONFIG_WITH_VALUE_LENGTH) + char num[11]; +#endif + + /* Clean up the name of the variable to be invoked. */ + fname = next_token (argv[0]); +#ifndef CONFIG_WITH_VALUE_LENGTH + end_of_token (fname)[0] = '\0'; +#else + fname_end = end_of_token (fname); + *fname_end = '\0'; +#endif + + /* Calling nothing is a no-op */ +#ifndef CONFIG_WITH_VALUE_LENGTH + if (*fname == '\0') +#else + if (fname == fname_end) +#endif + return o; + + /* Are we invoking a builtin function? */ + +#ifndef CONFIG_WITH_VALUE_LENGTH + entry_p = lookup_function (fname); +#else + entry_p = lookup_function (fname, fname_end - fname); +#endif + if (entry_p) + { + /* How many arguments do we have? */ + for (i=0; argv[i+1]; ++i) + ; + return expand_builtin_function (o, i, argv+1, entry_p); + } + + /* Not a builtin, so the first argument is the name of a variable to be + expanded and interpreted as a function. Find it. */ + flen = strlen (fname); + + v = lookup_variable (fname, flen); + + if (v == 0) + warn_undefined (fname, flen); + + if (v == 0 || *v->value == '\0') + return o; + + body = alloca (flen + 4); + body[0] = '$'; + body[1] = '('; + memcpy (body + 2, fname, flen); + body[flen+2] = ')'; + body[flen+3] = '\0'; + + /* Set up arguments $(1) .. $(N). $(0) is the function name. */ + + push_new_variable_scope (); + + for (i=0; *argv; ++i, ++argv) +#ifdef CONFIG_WITH_VALUE_LENGTH + define_variable (num, sprintf (num, "%d", i), *argv, o_automatic, 0); +#else + { + char num[11]; + + sprintf (num, "%d", i); + define_variable (num, strlen (num), *argv, o_automatic, 0); + } +#endif + +#ifdef CONFIG_WITH_EVALPLUS + /* $(.ARGC) is the argument count. */ + + len = sprintf (num, "%d", i - 1); + define_variable_vl (".ARGC", sizeof (".ARGC") - 1, num, len, + 1 /* dup val */, o_automatic, 0); +#endif + + /* If the number of arguments we have is < max_args, it means we're inside + a recursive invocation of $(call ...). Fill in the remaining arguments + in the new scope with the empty value, to hide them from this + invocation. */ + + for (; i < max_args; ++i) +#ifdef CONFIG_WITH_VALUE_LENGTH + define_variable (num, sprintf (num, "%d", i), "", o_automatic, 0); +#else + { + char num[11]; + + sprintf (num, "%d", i); + define_variable (num, strlen (num), "", o_automatic, 0); + } +#endif + + saved_args = max_args; + max_args = i; + +#ifdef CONFIG_WITH_EVALPLUS + if (!strcmp (funcname, "call")) + { +#endif + /* Expand the body in the context of the arguments, adding the result to + the variable buffer. */ + + v->exp_count = EXP_COUNT_MAX; +#ifndef CONFIG_WITH_VALUE_LENGTH + o = variable_expand_string (o, body, flen+3); + v->exp_count = 0; + + o += strlen (o); +#else /* CONFIG_WITH_VALUE_LENGTH */ + variable_expand_string_2 (o, body, flen+3, &o); + v->exp_count = 0; +#endif /* CONFIG_WITH_VALUE_LENGTH */ +#ifdef CONFIG_WITH_EVALPLUS + } + else + { + const floc *reading_file_saved = reading_file; + char *eos; + + if (!strcmp (funcname, "evalcall")) + { + /* Evaluate the variable value without expanding it. We + need a copy since eval_buffer is destructive. */ + + size_t off = o - variable_buffer; + eos = variable_buffer_output (o, v->value, v->value_length + 1) - 1; + o = variable_buffer + off; + if (v->fileinfo.filenm) + reading_file = &v->fileinfo; + } + else + { + /* Expand the body first and then evaluate the output. */ + + v->exp_count = EXP_COUNT_MAX; + o = variable_expand_string_2 (o, body, flen+3, &eos); + v->exp_count = 0; + } + + install_variable_buffer (&buf, &len); + eval_buffer (o, NULL, eos); + restore_variable_buffer (buf, len); + reading_file = reading_file_saved; + + /* Deal with the .RETURN value if present. */ + + v = lookup_variable_in_set (".RETURN", sizeof (".RETURN") - 1, + current_variable_set_list->set); + if (v && v->value_length) + { + if (v->recursive && !IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR (v)) + { + v->exp_count = EXP_COUNT_MAX; + variable_expand_string_2 (o, v->value, v->value_length, &o); + v->exp_count = 0; + } + else + o = variable_buffer_output (o, v->value, v->value_length); + } + } +#endif /* CONFIG_WITH_EVALPLUS */ + + max_args = saved_args; + + pop_variable_scope (); + + return o; +} + +void +define_new_function (const floc *flocp, const char *name, + unsigned int min, unsigned int max, unsigned int flags, + gmk_func_ptr func) +{ + const char *e = name; + struct function_table_entry *ent; + size_t len; + + while (STOP_SET (*e, MAP_USERFUNC)) + e++; + len = e - name; + + if (len == 0) + O (fatal, flocp, _("Empty function name")); + if (*name == '.' || *e != '\0') + OS (fatal, flocp, _("Invalid function name: %s"), name); + if (len > 255) + OS (fatal, flocp, _("Function name too long: %s"), name); + if (min > 255) + ONS (fatal, flocp, + _("Invalid minimum argument count (%u) for function %s"), min, name); + if (max > 255 || (max && max < min)) + ONS (fatal, flocp, + _("Invalid maximum argument count (%u) for function %s"), max, name); + + ent = xmalloc (sizeof (struct function_table_entry)); + ent->name = name; + ent->len = len; + ent->minimum_args = min; + ent->maximum_args = max; + ent->expand_args = ANY_SET(flags, GMK_FUNC_NOEXPAND) ? 0 : 1; + ent->alloc_fn = 1; + ent->fptr.alloc_func_ptr = func; + + hash_insert (&function_table, ent); +} + +void +hash_init_function_table (void) +{ + hash_init (&function_table, FUNCTION_TABLE_ENTRIES * 2, + function_table_entry_hash_1, function_table_entry_hash_2, + function_table_entry_hash_cmp); + hash_load (&function_table, function_table_init, + FUNCTION_TABLE_ENTRIES, sizeof (struct function_table_entry)); +#if defined (CONFIG_WITH_OPTIMIZATION_HACKS) || defined (CONFIG_WITH_VALUE_LENGTH) + { + unsigned int i; + for (i = 0; i < FUNCTION_TABLE_ENTRIES; i++) + { + const char *fn = function_table_init[i].name; + while (*fn) + { + func_char_map[(int)*fn] = 1; + fn++; + } + assert (function_table_init[i].len <= MAX_FUNCTION_LENGTH); + assert (function_table_init[i].len >= MIN_FUNCTION_LENGTH); + } + } +#endif +} diff --git a/src/kmk/getloadavg.c b/src/kmk/getloadavg.c new file mode 100644 index 0000000..10ae56a --- /dev/null +++ b/src/kmk/getloadavg.c @@ -0,0 +1,1026 @@ +/* Get the system load averages. +Copyright (C) 1985-2016 Free Software Foundation, Inc. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +/* Compile-time symbols that this file uses: + + HAVE_PSTAT_GETDYNAMIC Define this if your system has the + pstat_getdynamic function. I think it + is unique to HPUX9. The best way to get the + definition is through the AC_FUNC_GETLOADAVG + macro that comes with autoconf 2.13 or newer. + If that isn't an option, then just put + AC_CHECK_FUNCS(pstat_getdynamic) in your + configure.in file. + FIXUP_KERNEL_SYMBOL_ADDR() Adjust address in returned struct nlist. + KERNEL_FILE Pathname of the kernel to nlist. + LDAV_CVT() Scale the load average from the kernel. + Returns a double. + LDAV_SYMBOL Name of kernel symbol giving load average. + LOAD_AVE_TYPE Type of the load average array in the kernel. + Must be defined unless one of + apollo, DGUX, NeXT, or UMAX is defined; + or we have libkstat; + otherwise, no load average is available. + NLIST_STRUCT Include nlist.h, not a.out.h, and + the nlist n_name element is a pointer, + not an array. + HAVE_STRUCT_NLIST_N_UN_N_NAME struct nlist has an n_un member, not n_name. + LINUX_LDAV_FILE [__linux__]: File containing load averages. + + Specific system predefines this file uses, aside from setting + default values if not emacs: + + apollo + BSD Real BSD, not just BSD-like. + convex + DGUX + eunice UNIX emulator under VMS. + hpux + __MSDOS__ No-op for MSDOS. + NeXT + sgi + sequent Sequent Dynix 3.x.x (BSD) + _SEQUENT_ Sequent DYNIX/ptx 1.x.x (SYSV) + sony_news NEWS-OS (works at least for 4.1C) + UMAX + UMAX4_3 + VMS + WINDOWS32 No-op for Windows95/NT. + __linux__ Linux: assumes /proc filesystem mounted. + Support from Michael K. Johnson. + __NetBSD__ NetBSD: assumes /kern filesystem mounted. + + In addition, to avoid nesting many #ifdefs, we internally set + LDAV_DONE to indicate that the load average has been computed. + + We also #define LDAV_PRIVILEGED if a program will require + special installation to be able to call getloadavg. */ + +/* This should always be first. */ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +/* Both the Emacs and non-Emacs sections want this. Some + configuration files' definitions for the LOAD_AVE_CVT macro (like + sparc.h's) use macros like FSCALE, defined here. */ +#if defined (unix) || defined (__unix) +# include +#endif + + +/* Exclude all the code except the test program at the end + if the system has its own 'getloadavg' function. + + The declaration of 'errno' is needed by the test program + as well as the function itself, so it comes first. */ + +#include + +#ifndef errno +extern int errno; +#endif + +#if HAVE_LOCALE_H +# include +#endif +#if !HAVE_SETLOCALE +# define setlocale(Category, Locale) /* empty */ +#endif + +#ifndef HAVE_GETLOADAVG + + +/* The existing Emacs configuration files define a macro called + LOAD_AVE_CVT, which accepts a value of type LOAD_AVE_TYPE, and + returns the load average multiplied by 100. What we actually want + is a macro called LDAV_CVT, which returns the load average as an + unmultiplied double. + + For backwards compatibility, we'll define LDAV_CVT in terms of + LOAD_AVE_CVT, but future machine config files should just define + LDAV_CVT directly. */ + +# if !defined(LDAV_CVT) && defined(LOAD_AVE_CVT) +# define LDAV_CVT(n) (LOAD_AVE_CVT (n) / 100.0) +# endif + +# if !defined (BSD) && defined (ultrix) +/* Ultrix behaves like BSD on Vaxen. */ +# define BSD +# endif + +# ifdef NeXT +/* NeXT in the 2.{0,1,2} releases defines BSD in , which + conflicts with the definition understood in this file, that this + really is BSD. */ +# undef BSD + +/* NeXT defines FSCALE in . However, we take FSCALE being + defined to mean that the nlist method should be used, which is not true. */ +# undef FSCALE +# endif + +/* Same issues as for NeXT apply to the HURD-based GNU system. */ +# ifdef __GNU__ +# undef BSD +# undef FSCALE +# endif /* __GNU__ */ + +/* Set values that are different from the defaults, which are + set a little farther down with #ifndef. */ + + +/* Some shorthands. */ + +# if defined (HPUX) && !defined (hpux) +# define hpux +# endif + +# if defined (__hpux) && !defined (hpux) +# define hpux +# endif + +# if defined (__sun) && !defined (sun) +# define sun +# endif + +# if defined(hp300) && !defined(hpux) +# define MORE_BSD +# endif + +# if defined(ultrix) && defined(mips) +# define decstation +# endif + +# if defined (__SVR4) && !defined (SVR4) +# define SVR4 +# endif + +# if (defined(sun) && defined(SVR4)) || defined (SOLARIS2) +# define SUNOS_5 +# endif + +# if defined (__osf__) && (defined (__alpha) || defined (__alpha__)) +# define OSF_ALPHA +# include +# include +# include +# include +# endif + +# if defined (__osf__) && (defined (mips) || defined (__mips__)) +# define OSF_MIPS +# include +# endif + +/* UTek's /bin/cc on the 4300 has no architecture specific cpp define by + default, but _MACH_IND_SYS_TYPES is defined in . Combine + that with a couple of other things and we'll have a unique match. */ +# if !defined (tek4300) && defined (unix) && defined (m68k) && defined (mc68000) && defined (mc68020) && defined (_MACH_IND_SYS_TYPES) +# define tek4300 /* Define by emacs, but not by other users. */ +# endif + +/* AC_FUNC_GETLOADAVG thinks QNX is SVR4, but it isn't. */ +# if defined(__QNX__) +# undef SVR4 +# endif + +/* VAX C can't handle multi-line #ifs, or lines longer than 256 chars. */ +# ifndef LOAD_AVE_TYPE + +# ifdef MORE_BSD +# define LOAD_AVE_TYPE long +# endif + +# ifdef sun +# define LOAD_AVE_TYPE long +# endif + +# ifdef decstation +# define LOAD_AVE_TYPE long +# endif + +# ifdef _SEQUENT_ +# define LOAD_AVE_TYPE long +# endif + +# ifdef sgi +# define LOAD_AVE_TYPE long +# endif + +# ifdef SVR4 +# define LOAD_AVE_TYPE long +# endif + +# ifdef sony_news +# define LOAD_AVE_TYPE long +# endif + +# ifdef sequent +# define LOAD_AVE_TYPE long +# endif + +# ifdef OSF_ALPHA +# define LOAD_AVE_TYPE long +# endif + +# if defined (ardent) && defined (titan) +# define LOAD_AVE_TYPE long +# endif + +# ifdef tek4300 +# define LOAD_AVE_TYPE long +# endif + +# if defined(alliant) && defined(i860) /* Alliant FX/2800 */ +# define LOAD_AVE_TYPE long +# endif + +# ifdef _AIX +# define LOAD_AVE_TYPE long +# endif + +# ifdef convex +# define LOAD_AVE_TYPE double +# ifndef LDAV_CVT +# define LDAV_CVT(n) (n) +# endif +# endif + +# endif /* No LOAD_AVE_TYPE. */ + +# ifdef OSF_ALPHA +/* defines an incorrect value for FSCALE on Alpha OSF/1, + according to ghazi@noc.rutgers.edu. */ +# undef FSCALE +# define FSCALE 1024.0 +# endif + +# if defined(alliant) && defined(i860) /* Alliant FX/2800 */ +/* defines an incorrect value for FSCALE on an + Alliant FX/2800 Concentrix 2.2, according to ghazi@noc.rutgers.edu. */ +# undef FSCALE +# define FSCALE 100.0 +# endif + + +# ifndef FSCALE + +/* SunOS and some others define FSCALE in sys/param.h. */ + +# ifdef MORE_BSD +# define FSCALE 2048.0 +# endif + +# if defined(MIPS) || defined(SVR4) || defined(decstation) +# define FSCALE 256 +# endif + +# if defined (sgi) || defined (sequent) +/* Sometimes both MIPS and sgi are defined, so FSCALE was just defined + above under #ifdef MIPS. But we want the sgi value. */ +# undef FSCALE +# define FSCALE 1000.0 +# endif + +# if defined (ardent) && defined (titan) +# define FSCALE 65536.0 +# endif + +# ifdef tek4300 +# define FSCALE 100.0 +# endif + +# ifdef _AIX +# define FSCALE 65536.0 +# endif + +# endif /* Not FSCALE. */ + +# if !defined (LDAV_CVT) && defined (FSCALE) +# define LDAV_CVT(n) (((double) (n)) / FSCALE) +# endif + + +# if defined(sgi) || (defined(mips) && !defined(BSD)) +# define FIXUP_KERNEL_SYMBOL_ADDR(nl) ((nl)[0].n_value &= ~(1 << 31)) +# endif + + +# if !defined (KERNEL_FILE) && defined (sequent) +# define KERNEL_FILE "/dynix" +# endif + +# if !defined (KERNEL_FILE) && defined (hpux) +# define KERNEL_FILE "/hp-ux" +# endif + +# if !defined(KERNEL_FILE) && (defined(_SEQUENT_) || defined(MIPS) || defined(SVR4) || defined(ISC) || defined (sgi) || (defined (ardent) && defined (titan))) +# define KERNEL_FILE "/unix" +# endif + + +# if !defined (LDAV_SYMBOL) && defined (alliant) +# define LDAV_SYMBOL "_Loadavg" +# endif + +# if !defined(LDAV_SYMBOL) && ((defined(hpux) && !defined(hp9000s300)) || defined(_SEQUENT_) || defined(SVR4) || defined(ISC) || defined(sgi) || (defined (ardent) && defined (titan)) || defined (_AIX)) +# define LDAV_SYMBOL "avenrun" +# endif + +# ifdef HAVE_UNISTD_H +# include +# endif + +# include + +/* LOAD_AVE_TYPE should only get defined if we're going to use the + nlist method. */ +# if !defined(LOAD_AVE_TYPE) && (defined(BSD) || defined(LDAV_CVT) || defined(KERNEL_FILE) || defined(LDAV_SYMBOL)) && !defined(__riscos__) +# define LOAD_AVE_TYPE double +# endif + +# ifdef LOAD_AVE_TYPE + +# ifndef VMS +# ifndef __linux__ +# ifdef HAVE_NLIST_H +# include +# else +# include +# endif + +# ifdef SUNOS_5 +# include +# include +# include +# endif + +# if defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC) +# include +# endif + +# ifndef KERNEL_FILE +# define KERNEL_FILE "/vmunix" +# endif /* KERNEL_FILE */ + +# ifndef LDAV_SYMBOL +# define LDAV_SYMBOL "_avenrun" +# endif /* LDAV_SYMBOL */ +# endif /* __linux__ */ + +# else /* VMS */ + +# ifndef eunice +# include +# include +# else /* eunice */ +# include +# endif /* eunice */ +# endif /* VMS */ + +# ifndef LDAV_CVT +# define LDAV_CVT(n) ((double) (n)) +# endif /* !LDAV_CVT */ + +# endif /* LOAD_AVE_TYPE */ + +# if defined(__GNU__) && !defined (NeXT) +/* Note that NeXT Openstep defines __GNU__ even though it should not. */ +/* GNU system acts much like NeXT, for load average purposes, + but not exactly. */ +# define NeXT +# define host_self mach_host_self +# endif + +# ifdef NeXT +# ifdef HAVE_MACH_MACH_H +# include +# else +# include +# endif +# endif /* NeXT */ + +# ifdef sgi +# include +# endif /* sgi */ + +# ifdef UMAX +# include +# include +# include +# include +# include + +# ifdef UMAX_43 +# include +# include +# include +# include +# include +# else /* Not UMAX_43. */ +# include +# include +# include +# include +# include +# include +# endif /* Not UMAX_43. */ +# endif /* UMAX */ + +# ifdef DGUX +# include +# endif + +# if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION) +# include +# else +# include +# endif + + +/* Avoid static vars inside a function since in HPUX they dump as pure. */ + +# ifdef NeXT +static processor_set_t default_set; +static int getloadavg_initialized; +# endif /* NeXT */ + +# ifdef UMAX +static unsigned int cpus = 0; +static unsigned int samples; +# endif /* UMAX */ + +# ifdef DGUX +static struct dg_sys_info_load_info load_info; /* what-a-mouthful! */ +# endif /* DGUX */ + +#if !defined(HAVE_LIBKSTAT) && defined(LOAD_AVE_TYPE) +/* File descriptor open to /dev/kmem or VMS load ave driver. */ +static int channel; +/* Nonzero iff channel is valid. */ +static int getloadavg_initialized; +/* Offset in kmem to seek to read load average, or 0 means invalid. */ +static long offset; + +#if !defined(VMS) && !defined(sgi) && !defined(__linux__) +static struct nlist nl[2]; +#endif /* Not VMS or sgi */ + +#ifdef SUNOS_5 +static kvm_t *kd; +#endif /* SUNOS_5 */ + +#endif /* LOAD_AVE_TYPE && !HAVE_LIBKSTAT */ + +/* Put the 1 minute, 5 minute and 15 minute load averages + into the first NELEM elements of LOADAVG. + Return the number written (never more than 3, but may be less than NELEM), + or -1 if an error occurred. */ + +int +getloadavg (double loadavg[], int nelem) +{ + int elem = 0; /* Return value. */ + +# ifdef NO_GET_LOAD_AVG +# define LDAV_DONE + /* Set errno to zero to indicate that there was no particular error; + this function just can't work at all on this system. */ + errno = 0; + elem = -1; +# endif + +# if !defined (LDAV_DONE) && defined (HAVE_LIBKSTAT) +/* Use libkstat because we don't have to be root. */ +# define LDAV_DONE + kstat_ctl_t *kc; + kstat_t *ksp; + kstat_named_t *kn; + + kc = kstat_open (); + if (kc == 0) + return -1; + ksp = kstat_lookup (kc, "unix", 0, "system_misc"); + if (ksp == 0 ) + return -1; + if (kstat_read (kc, ksp, 0) == -1) + return -1; + + + kn = kstat_data_lookup (ksp, "avenrun_1min"); + if (kn == 0) + { + /* Return -1 if no load average information is available. */ + nelem = 0; + elem = -1; + } + + if (nelem >= 1) + loadavg[elem++] = (double) kn->value.ul/FSCALE; + + if (nelem >= 2) + { + kn = kstat_data_lookup (ksp, "avenrun_5min"); + if (kn != 0) + { + loadavg[elem++] = (double) kn->value.ul/FSCALE; + + if (nelem >= 3) + { + kn = kstat_data_lookup (ksp, "avenrun_15min"); + if (kn != 0) + loadavg[elem++] = (double) kn->value.ul/FSCALE; + } + } + } + + kstat_close (kc); +# endif /* HAVE_LIBKSTAT */ + +# if !defined (LDAV_DONE) && defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC) +/* Use pstat_getdynamic() because we don't have to be root. */ +# define LDAV_DONE +# undef LOAD_AVE_TYPE + + struct pst_dynamic dyn_info; + if (pstat_getdynamic (&dyn_info, sizeof (dyn_info), 0, 0) < 0) + return -1; + if (nelem > 0) + loadavg[elem++] = dyn_info.psd_avg_1_min; + if (nelem > 1) + loadavg[elem++] = dyn_info.psd_avg_5_min; + if (nelem > 2) + loadavg[elem++] = dyn_info.psd_avg_15_min; + +# endif /* hpux && HAVE_PSTAT_GETDYNAMIC */ + +# if !defined (LDAV_DONE) && defined (__linux__) +# define LDAV_DONE +# undef LOAD_AVE_TYPE + +# ifndef LINUX_LDAV_FILE +# define LINUX_LDAV_FILE "/proc/loadavg" +# endif + + char ldavgbuf[40]; + double load_ave[3]; + int fd, count; + + fd = open (LINUX_LDAV_FILE, O_RDONLY); + if (fd == -1) + return -1; + count = read (fd, ldavgbuf, 40); + (void) close (fd); + if (count <= 0) + return -1; + + /* The following sscanf must use the C locale. */ + setlocale (LC_NUMERIC, "C"); + count = sscanf (ldavgbuf, "%lf %lf %lf", + &load_ave[0], &load_ave[1], &load_ave[2]); + setlocale (LC_NUMERIC, ""); + if (count < 1) + return -1; + + for (elem = 0; elem < nelem && elem < count; elem++) + loadavg[elem] = load_ave[elem]; + + return elem; + +# endif /* __linux__ */ + +# if !defined (LDAV_DONE) && defined (__NetBSD__) +# define LDAV_DONE +# undef LOAD_AVE_TYPE + +# ifndef NETBSD_LDAV_FILE +# define NETBSD_LDAV_FILE "/kern/loadavg" +# endif + + unsigned long int load_ave[3], scale; + int count; + FILE *fp; + + fp = fopen (NETBSD_LDAV_FILE, "r"); + if (fp == NULL) + return -1; + count = fscanf (fp, "%lu %lu %lu %lu\n", + &load_ave[0], &load_ave[1], &load_ave[2], + &scale); + (void) fclose (fp); + if (count != 4) + return -1; + + for (elem = 0; elem < nelem; elem++) + loadavg[elem] = (double) load_ave[elem] / (double) scale; + + return elem; + +# endif /* __NetBSD__ */ + +# if !defined (LDAV_DONE) && defined (NeXT) +# define LDAV_DONE + /* The NeXT code was adapted from iscreen 3.2. */ + + host_t host; + struct processor_set_basic_info info; + unsigned info_count; + + /* We only know how to get the 1-minute average for this system, + so even if the caller asks for more than 1, we only return 1. */ + + if (!getloadavg_initialized) + { + if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS) + getloadavg_initialized = 1; + } + + if (getloadavg_initialized) + { + info_count = PROCESSOR_SET_BASIC_INFO_COUNT; + if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host, + (processor_set_info_t) &info, &info_count) + != KERN_SUCCESS) + getloadavg_initialized = 0; + else + { + if (nelem > 0) + loadavg[elem++] = (double) info.load_average / LOAD_SCALE; + } + } + + if (!getloadavg_initialized) + return -1; +# endif /* NeXT */ + +# if !defined (LDAV_DONE) && defined (UMAX) +# define LDAV_DONE +/* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not + have a /dev/kmem. Information about the workings of the running kernel + can be gathered with inq_stats system calls. + We only know how to get the 1-minute average for this system. */ + + struct proc_summary proc_sum_data; + struct stat_descr proc_info; + double load; + register unsigned int i, j; + + if (cpus == 0) + { + register unsigned int c, i; + struct cpu_config conf; + struct stat_descr desc; + + desc.sd_next = 0; + desc.sd_subsys = SUBSYS_CPU; + desc.sd_type = CPUTYPE_CONFIG; + desc.sd_addr = (char *) &conf; + desc.sd_size = sizeof conf; + + if (inq_stats (1, &desc)) + return -1; + + c = 0; + for (i = 0; i < conf.config_maxclass; ++i) + { + struct class_stats stats; + memset (&stats, '\0', sizeof stats); + + desc.sd_type = CPUTYPE_CLASS; + desc.sd_objid = i; + desc.sd_addr = (char *) &stats; + desc.sd_size = sizeof stats; + + if (inq_stats (1, &desc)) + return -1; + + c += stats.class_numcpus; + } + cpus = c; + samples = cpus < 2 ? 3 : (2 * cpus / 3); + } + + proc_info.sd_next = 0; + proc_info.sd_subsys = SUBSYS_PROC; + proc_info.sd_type = PROCTYPE_SUMMARY; + proc_info.sd_addr = (char *) &proc_sum_data; + proc_info.sd_size = sizeof (struct proc_summary); + proc_info.sd_sizeused = 0; + + if (inq_stats (1, &proc_info) != 0) + return -1; + + load = proc_sum_data.ps_nrunnable; + j = 0; + for (i = samples - 1; i > 0; --i) + { + load += proc_sum_data.ps_nrun[j]; + if (j++ == PS_NRUNSIZE) + j = 0; + } + + if (nelem > 0) + loadavg[elem++] = load / samples / cpus; +# endif /* UMAX */ + +# if !defined (LDAV_DONE) && defined (DGUX) +# define LDAV_DONE + /* This call can return -1 for an error, but with good args + it's not supposed to fail. The first argument is for no + apparent reason of type 'long int *'. */ + dg_sys_info ((long int *) &load_info, + DG_SYS_INFO_LOAD_INFO_TYPE, + DG_SYS_INFO_LOAD_VERSION_0); + + if (nelem > 0) + loadavg[elem++] = load_info.one_minute; + if (nelem > 1) + loadavg[elem++] = load_info.five_minute; + if (nelem > 2) + loadavg[elem++] = load_info.fifteen_minute; +# endif /* DGUX */ + +# if !defined (LDAV_DONE) && defined (apollo) +# define LDAV_DONE +/* Apollo code from lisch@mentorg.com (Ray Lischner). + + This system call is not documented. The load average is obtained as + three long integers, for the load average over the past minute, + five minutes, and fifteen minutes. Each value is a scaled integer, + with 16 bits of integer part and 16 bits of fraction part. + + I'm not sure which operating system first supported this system call, + but I know that SR10.2 supports it. */ + + extern void proc1_$get_loadav (); + unsigned long load_ave[3]; + + proc1_$get_loadav (load_ave); + + if (nelem > 0) + loadavg[elem++] = load_ave[0] / 65536.0; + if (nelem > 1) + loadavg[elem++] = load_ave[1] / 65536.0; + if (nelem > 2) + loadavg[elem++] = load_ave[2] / 65536.0; +# endif /* apollo */ + +# if !defined (LDAV_DONE) && defined (OSF_MIPS) +# define LDAV_DONE + + struct tbl_loadavg load_ave; + table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave)); + loadavg[elem++] + = (load_ave.tl_lscale == 0 + ? load_ave.tl_avenrun.d[0] + : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale)); +# endif /* OSF_MIPS */ + +# if !defined (LDAV_DONE) && (defined (__MSDOS__) || defined (WINDOWS32)) +# define LDAV_DONE + + /* A faithful emulation is going to have to be saved for a rainy day. */ + for ( ; elem < nelem; elem++) + { + loadavg[elem] = 0.0; + } +# endif /* __MSDOS__ || WINDOWS32 */ + +# if !defined (LDAV_DONE) && defined (OSF_ALPHA) +# define LDAV_DONE + + struct tbl_loadavg load_ave; + table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave)); + for (elem = 0; elem < nelem; elem++) + loadavg[elem] + = (load_ave.tl_lscale == 0 + ? load_ave.tl_avenrun.d[elem] + : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale)); +# endif /* OSF_ALPHA */ + +# if !defined (LDAV_DONE) && defined (VMS) + /* VMS specific code -- read from the Load Ave driver. */ + + LOAD_AVE_TYPE load_ave[3]; + static int getloadavg_initialized = 0; +# ifdef eunice + struct + { + int dsc$w_length; + char *dsc$a_pointer; + } descriptor; +# endif + + /* Ensure that there is a channel open to the load ave device. */ + if (!getloadavg_initialized) + { + /* Attempt to open the channel. */ +# ifdef eunice + descriptor.dsc$w_length = 18; + descriptor.dsc$a_pointer = "$$VMS_LOAD_AVERAGE"; +# else + $DESCRIPTOR (descriptor, "LAV0:"); +# endif + if (sys$assign (&descriptor, &channel, 0, 0) & 1) + getloadavg_initialized = 1; + } + + /* Read the load average vector. */ + if (getloadavg_initialized + && !(sys$qiow (0, channel, IO$_READVBLK, 0, 0, 0, + load_ave, 12, 0, 0, 0, 0) & 1)) + { + sys$dassgn (channel); + getloadavg_initialized = 0; + } + + if (!getloadavg_initialized) + return -1; +# endif /* VMS */ + +# if !defined (LDAV_DONE) && defined(LOAD_AVE_TYPE) && !defined(VMS) + + /* UNIX-specific code -- read the average from /dev/kmem. */ + +# define LDAV_PRIVILEGED /* This code requires special installation. */ + + LOAD_AVE_TYPE load_ave[3]; + + /* Get the address of LDAV_SYMBOL. */ + if (offset == 0) + { +# ifndef sgi +# ifndef NLIST_STRUCT + strcpy (nl[0].n_name, LDAV_SYMBOL); + strcpy (nl[1].n_name, ""); +# else /* NLIST_STRUCT */ +# ifdef HAVE_STRUCT_NLIST_N_UN_N_NAME + nl[0].n_un.n_name = LDAV_SYMBOL; + nl[1].n_un.n_name = 0; +# else /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */ + nl[0].n_name = LDAV_SYMBOL; + nl[1].n_name = 0; +# endif /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */ +# endif /* NLIST_STRUCT */ + +# ifndef SUNOS_5 + if ( +# if !(defined (_AIX) && !defined (ps2)) + nlist (KERNEL_FILE, nl) +# else /* _AIX */ + knlist (nl, 1, sizeof (nl[0])) +# endif + >= 0) + /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i. */ + { +# ifdef FIXUP_KERNEL_SYMBOL_ADDR + FIXUP_KERNEL_SYMBOL_ADDR (nl); +# endif + offset = nl[0].n_value; + } +# endif /* !SUNOS_5 */ +# else /* sgi */ + int ldav_off; + + ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN); + if (ldav_off != -1) + offset = (long) ldav_off & 0x7fffffff; +# endif /* sgi */ + } + + /* Make sure we have /dev/kmem open. */ + if (!getloadavg_initialized) + { +# ifndef SUNOS_5 + channel = open ("/dev/kmem", 0); + if (channel >= 0) + { + /* Set the channel to close on exec, so it does not + litter any child's descriptor table. */ +# ifdef F_SETFD +# ifndef FD_CLOEXEC +# define FD_CLOEXEC 1 +# endif + (void) fcntl (channel, F_SETFD, FD_CLOEXEC); +# endif + getloadavg_initialized = 1; + } +# else /* SUNOS_5 */ + /* We pass 0 for the kernel, corefile, and swapfile names + to use the currently running kernel. */ + kd = kvm_open (0, 0, 0, O_RDONLY, 0); + if (kd != 0) + { + /* nlist the currently running kernel. */ + kvm_nlist (kd, nl); + offset = nl[0].n_value; + getloadavg_initialized = 1; + } +# endif /* SUNOS_5 */ + } + + /* If we can, get the load average values. */ + if (offset && getloadavg_initialized) + { + /* Try to read the load. */ +# ifndef SUNOS_5 + if (lseek (channel, offset, 0) == -1L + || read (channel, (char *) load_ave, sizeof (load_ave)) + != sizeof (load_ave)) + { + close (channel); + getloadavg_initialized = 0; + } +# else /* SUNOS_5 */ + if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave)) + != sizeof (load_ave)) + { + kvm_close (kd); + getloadavg_initialized = 0; + } +# endif /* SUNOS_5 */ + } + + if (offset == 0 || !getloadavg_initialized) + return -1; +# endif /* LOAD_AVE_TYPE and not VMS */ + +# if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) /* Including VMS. */ + if (nelem > 0) + loadavg[elem++] = LDAV_CVT (load_ave[0]); + if (nelem > 1) + loadavg[elem++] = LDAV_CVT (load_ave[1]); + if (nelem > 2) + loadavg[elem++] = LDAV_CVT (load_ave[2]); + +# define LDAV_DONE +# endif /* !LDAV_DONE && LOAD_AVE_TYPE */ + +# ifdef LDAV_DONE + return elem; +# else + /* Set errno to zero to indicate that there was no particular error; + this function just can't work at all on this system. */ + errno = 0; + return -1; +# endif +} + +#endif /* ! HAVE_GETLOADAVG */ + +#ifdef TEST +#include "makeint.h" + +int +main (int argc, char **argv) +{ + int naptime = 0; + + if (argc > 1) + naptime = atoi (argv[1]); + + while (1) + { + double avg[3]; + int loads; + + errno = 0; /* Don't be misled if it doesn't set errno. */ + loads = getloadavg (avg, 3); + if (loads == -1) + { + perror ("Error getting load average"); + exit (1); + } + if (loads > 0) + printf ("1-minute: %f ", avg[0]); + if (loads > 1) + printf ("5-minute: %f ", avg[1]); + if (loads > 2) + printf ("15-minute: %f ", avg[2]); + if (loads > 0) + putchar ('\n'); + + if (naptime == 0) + break; + sleep (naptime); + } + + exit (0); +} +#endif /* TEST */ diff --git a/src/kmk/getopt.c b/src/kmk/getopt.c new file mode 100644 index 0000000..b7999ea --- /dev/null +++ b/src/kmk/getopt.c @@ -0,0 +1,1031 @@ +/* Getopt for GNU. +NOTE: getopt is now part of the C library, so if you don't know what +"Keep this file name-space clean" means, talk to drepper@gnu.org +before changing it! + +Copyright (C) 1987-2016 Free Software Foundation, Inc. + +NOTE: The canonical source of this file is maintained with the GNU C Library. +Bugs can be reported to bug-glibc@gnu.org. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +# define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +# ifndef const +# define const +# endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +# include +# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +# include +# include +#endif /* GNU C library. */ + +#ifdef VMS +# include +# if HAVE_STRING_H - 0 +# include +# endif +#endif + +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +#include "gettext.h" +#define _(msgid) gettext (msgid) + + +/* This version of `getopt' appears to the caller like standard Unix 'getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = NULL; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +# include +# define my_index strchr +#else + +# if HAVE_STRING_H +# include +# else +# include +# endif + +#ifndef KMK +/* Avoid depending on library functions or files + whose names are inconsistent. */ +#ifndef getenv +extern char *getenv (); +#endif +#else /* KMK */ +# include +#endif /* KMK */ + +static char * +my_index (const char *str, int chr) +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +# if (!defined __STDC__ || !__STDC__) && !defined strlen +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +# endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void __attribute__ ((unused)) +store_args_and_env (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} +# ifdef text_set_element +text_set_element (__libc_subinit, store_args_and_env); +# endif /* text_set_element */ + +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined __STDC__ && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (char **argv) +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#ifdef _LIBC + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memset (__mempcpy (new_str, __getopt_nonoption_flags, + nonoption_flags_max_len), + '\0', top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined __STDC__ && __STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (int argc, char *const *argv, const char *optstring) +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL + && argc == original_argc && argv == original_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), + '\0', nonoption_flags_max_len - len); + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longind, int long_only) +{ + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#ifdef _LIBC +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option '%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + { /* bird: disambiguate */ + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option '--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option '%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + } + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option '%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option '--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option '%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option '-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + fprintf (stderr, _("\ +%s: option '-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option '%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (int argc, char *const *argv, const char *optstring) +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (int argc, char **argv) +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value '%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/src/kmk/getopt.h b/src/kmk/getopt.h new file mode 100644 index 0000000..8713c12 --- /dev/null +++ b/src/kmk/getopt.h @@ -0,0 +1,132 @@ +/* Declarations for getopt. +Copyright (C) 1989-2016 Free Software Foundation, Inc. + +NOTE: The canonical source of this file is maintained with the GNU C Library. +Bugs can be reported to bug-glibc@gnu.org. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#ifndef FAKES_NO_GETOPT_H /* bird: hack for rhel4 unistd.h dragging in getopt.h */ +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if defined (__STDC__) && __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if defined (__STDC__) && __STDC__ +#ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* getopt.h */ +#endif /* bird hack */ diff --git a/src/kmk/getopt1.c b/src/kmk/getopt1.c new file mode 100644 index 0000000..0e38b2f --- /dev/null +++ b/src/kmk/getopt1.c @@ -0,0 +1,176 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. +Copyright (C) 1987-1994, 1996-2016 Free Software Foundation, Inc. + +NOTE: The canonical source of this file is maintained with the GNU C Library. +Bugs can be reported to bug-glibc@gnu.org. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "getopt.h" + +#if !defined __STDC__ || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (int argc, char *const *argv, const char *options, + const struct option *long_options, int *opt_index) +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (int argc, char *const *argv, const char *options, + const struct option *long_options, int *opt_index) +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include + +int +main (int argc, char **argv) +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value '%s'\n", optarg); + break; + + case 'd': + printf ("option d with value '%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/src/kmk/gettext.h b/src/kmk/gettext.h new file mode 100644 index 0000000..c48ffa0 --- /dev/null +++ b/src/kmk/gettext.h @@ -0,0 +1,57 @@ +/* Convenience header for conditional use of GNU . +Copyright (C) 1995-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +/* NLS can be disabled through the configure --disable-nls option. */ +#if ENABLE_NLS + +/* Get declarations of GNU message catalog functions. */ +# include + +#else + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ +# define gettext(Msgid) ((const char *) (Msgid)) +# define dgettext(Domainname, Msgid) ((const char *) (Msgid)) +# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid)) +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2)) +# define textdomain(Domainname) ((const char *) (Domainname)) +# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname)) +# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset)) + +#endif + +/* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ +#define gettext_noop(String) String + +#endif /* _LIBGETTEXT_H */ diff --git a/src/kmk/glob/COPYING.LIB b/src/kmk/glob/COPYING.LIB new file mode 100644 index 0000000..bbe3fe1 --- /dev/null +++ b/src/kmk/glob/COPYING.LIB @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/src/kmk/glob/ChangeLog b/src/kmk/glob/ChangeLog new file mode 100644 index 0000000..c543c85 --- /dev/null +++ b/src/kmk/glob/ChangeLog @@ -0,0 +1,191 @@ +2013-10-20 Paul Smith + + * glob.c (glob): Cherry-pick a471e96a5352a5f0bde6d32dd36d33524811a2b1 + from git://sourceware.org/git/glibc.git to fix SV 18123, + https://sourceware.org/bugzilla/show_bug.cgi?id=10278 + +2008-09-28 Juan Manuel Guerrero + + * glob.c (my_realloc) [__DJGPP__]: Don't define, and don't + redefine realloc to call it, since the DJGPP's realloc handles + NULL pointers correctly. + +2007-12-22 Juan Manuel Guerrero (tiny change) + + * glob.c [__GNU_LIBRARY__ && __DJGPP__]: Add a realloc + declaration that matches the one in the DJGPP libc. + +2006-02-24 Eli Zaretskii + + * glob.c (my_malloc) [WINDOWS32]: Provide a full ISO C prototype, + to avoid compiler warnings. + +2005-06-25 Paul D. Smith + + * fnmatch.h, glob.h [WINDOWS32]: Fix ifdefs in headers. + Fixes Savannah bug #13477. + +2005-03-11 Paul D. Smith + + * glob.c (glob_in_dir): Change FNM_CASEFOLD to be enabled if + HAVE_CASE_INSENSITIVE_FS is defined. + +2003-01-30 Paul D. Smith + + * glob.h: Patch for FreeBSD by Mike Barcroft + Reported by Gerald Pfeifer . On + FreeBSD, declare __size_t to simply size_t. + +2002-04-22 Paul D. Smith + + * Makefile.am: Use automake 1.6. + Use new automake condition USE_LOCAL_GLOB to decide whether or not + to build the local GNU glob library or use the system one. + +1999-09-12 Paul D. Smith + + * fnmatch.c: Last GLIBC version wouldn't compile outside of GLIBC + (undefined reference to internal_function). Update to the latest + version + +1999-09-11 Paul Eggert + + * glob.h (glob): If #defining to glob64, do this before + declaring it, so that all declarations and uses match, and + do not declare glob64, to avoid a declaration clash. + (globfree): Likewise with globfree64. + +1999-09-08 Eli Zaretskii + + * glob.c (prefix_array) [__MSDOS__,WINDOWS32]: Keep the trailing + slash unless DIRNAME is just "x:/". + +1999-09-06 Paul D. Smith + + * fnmatch.c: Update to latest version from GLIBC. + +1999-07-21 Paul D. Smith + + * glob.c, glob.h, fnmatch.c, fnmatch.h: Update to latest version + from GLIBC. + + * fnmatch.c (internal_fnmatch): Use K&R definition syntax, not ANSI. + (__strchrnul): This won't exist outside GLIBC, so create one. + + * glob.c: Move getlogin{,_r} prototypes below glob.h to get __P() + macro. + +1998-08-05 Paul D. Smith + + * configure.in: Remove; configuration for glob is handled by the + make configure.in. + +1998-07-29 Paul D. Smith + + * glob.c, fnmatch.c: New versions from the GLIBC folks (Ulrich + Drepper). Fixes a bug reported by Eli Zaretski. Integrates + DOS/Windows32 support. + +1998-07-27 Kaveh R. Ghazi + + * glob.c (glob): Cast away const on assignment of pattern to dirname. + Cast the return type of __alloca() for traditional C compilers. + +1998-07-23 Paul D. Smith + + * glob.c, fnmatch.c: New versions of these files from the GLIBC + folks (Ulrich Drepper). Had to re-integrate some DOS/Windows + code. + +1998-07-10 Paul D. Smith + + * glob.c (glob_in_dir): If no meta chars exist in PATTERN and + GLOB_NOCHECK is present, don't look for the file--whether it's + found or not, we'll always return it, so why bother searching? + + Also, if we are searching and there are no meta chars, don't + bother trying fnmatch() if the strcmp() fails. + +1998-05-30 Eli Zaretskii + + * glob.c (glob) [__MSDOS__, WINDOWS32]: Compute the directory and + filename parts of the pattern correctly when it includes a drive + spec. Disallow wildcards in the drive spec. Prevent recursion + when dirname is of the form "d:/" or "d:". + (prefix_array) [__MSDOS__, WINDOWS32]: Don't append a slash to + "d:/" and "d:". + +1998-05-13 Paul D. Smith + + * SMakefile, Makefile.ami, glob.c, glob.h, fnmatch.c: Updated from + the latest glibc version. + +1998-04-17 Paul D. Smith + + * configure.in: Create a config.h file instead of setting things + on the compile line. This is because when build.sh runs it merely + passes -DHAVE_CONFIG_H to the glob files, just as it does to the + make files. + * config.h.in: Created by autoheader. + +Tue Aug 12 10:52:34 1997 Paul D. Smith + + * configure.in: Require autoconf 2.12. + + * glob: Updates from latest GNU libc glob code. + + * glob.c,glob.h,fnmatch.h: Change all WIN32 references to WINDOWS32. + + * glob.h: OSF4 defines macros in such a way that GLOB_ALTDIRFUNC + is not defined. Added a test to the #if which defines it if + _GNU_SOURCE is defined; that's set by both glob.c and GNU make. + + * glob.c: SunOS4 w/ cc needs #include , since assert.h + requires stderr but doesn't include stdio.h :-/. + (next_brace_sub): De-protoize function definition. + (glob): Cast __alloca(); on SunOS4 it uses the default return type + of int. + (glob): Irix defines getlogin_r() to return a char*; move the + extern for that into the _LIBC area since it isn't used except in + LIBC anyway. Likewise, move extern getlogin() into the "else". + +Sat Jul 20 21:55:31 1996 Roland McGrath + + Win32 hacks from . + * posix/glob.c [WIN32]: Don't include ; don't use d_ino; + use void * for my_realloc; include for alloca. + (glob) [WIN32]: Use "c:/users/default" for ~ if no HOME variable. + * posix/fnmatch.h [WIN32]: Use prototypes even if [!__STDC__]. + * posix/glob.h: Likewise. + +Fri Jul 19 16:56:41 1996 Roland McGrath + + * posix/glob.h [!_AMIGA && !VMS]: Check this instead of just [!_AMIGA] + for `struct stat;' forward decl. + +Sat Jun 22 10:44:09 1996 Roland McGrath + + * posix/glob.c: Include only [HAVE_ALLOCA_H], not [sparc]. + +Fri Jun 21 00:27:51 1996 Roland McGrath + + * posix/fnmatch.c (fnmatch): Fix \*[*?]+ case to increment name ptr + only for ?s, not for *s. Fix from Chet Ramey. + + +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software +Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . diff --git a/src/kmk/glob/Makefile.am b/src/kmk/glob/Makefile.am new file mode 100644 index 0000000..93fd60a --- /dev/null +++ b/src/kmk/glob/Makefile.am @@ -0,0 +1,30 @@ +# -*-Makefile-*-, or close enough +# Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. +# This file is part of GNU Make. +# +# GNU Make is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +AUTOMAKE_OPTIONS = foreign + +# Only build the library when the system doesn't already have GNU glob. +if USE_LOCAL_GLOB + noinst_LIBRARIES = libglob.a +endif + +libglob_a_SOURCES = glob.c glob.h fnmatch.c fnmatch.h + + +EXTRA_DIST = COPYING.LIB Makefile.ami SCOPTIONS SMakefile \ + configure.bat diff --git a/src/kmk/glob/Makefile.ami b/src/kmk/glob/Makefile.ami new file mode 100644 index 0000000..3fbf7e5 --- /dev/null +++ b/src/kmk/glob/Makefile.ami @@ -0,0 +1,67 @@ +# Makefile for standalone libglob.a (fnmatch, glob). -*-Makefile-*- +# Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007 Free Software Foundation, Inc. +# This file is part of GNU Make. +# +# GNU Make is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +# Ultrix 2.2 make doesn't expand the value of VPATH. +VPATH = /glob/ +# This must repeat the value, because configure will remove `VPATH = .'. +srcdir = /glob/ + +CC = sc +RM = delete +CPPFLAGS = +CFLAGS = + +# Information determined by configure. +DEFS = Define HAVE_HEADER_STDC Define HAVE_UNISTD_H Define HAVE_STRING_H \ + Define HAVE_DIRENT_H + +# How to invoke ar. +AR = join +ARFLAGS = as + +# How to invoke ranlib. +RANLIB = ; + +.PHONY: all +all: glob.lib + +glob.lib : glob.o fnmatch.o + $(AR) $(ARFLAGS) $@ glob.o fnmatch.o + $(RANLIB) $@ + +# For some reason, Unix make wants the dependencies on the source files. +# Otherwise it refuses to use an implicit rule! +# And, get this: it doesn't work to use $(srcdir)foo.c!! +glob.o: $(srcdir)glob.h $(srcdir)fnmatch.h glob.c +fnmatch.o: $(srcdir)fnmatch.h fnmatch.c + +OUTPUT_OPTION = +.c.o: + $(CC) IDir "" \ + $(DEFS) $(CPPFLAGS) $(CFLAGS) $< $(OUTPUT_OPTION) + +.PHONY: clean realclean glob-clean glob-realclean distclean +clean glob-clean: + -$(RM) glob.lib "#?.o" core +distclean glob-realclean: clean + -$(RM) TAGS tags Makefile config.status config.h config.log +realcean: distclean + +# For inside the C library. +glob.tar glob.tar.Z: + $(MAKE) -C .. $@ diff --git a/src/kmk/glob/SCOPTIONS b/src/kmk/glob/SCOPTIONS new file mode 100644 index 0000000..f89daae --- /dev/null +++ b/src/kmk/glob/SCOPTIONS @@ -0,0 +1,13 @@ +ERRORREXX +OPTIMIZE +NOVERSION +OPTIMIZERTIME +OPTIMIZERALIAS +DEFINE INCLUDEDIR="include:" +DEFINE LIBDIR="lib:" +DEFINE NO_ALLOCA +DEFINE NO_FLOAT +DEFINE NO_ARCHIVES +IGNORE=161 +IGNORE=100 +STARTUP=cres diff --git a/src/kmk/glob/SMakefile b/src/kmk/glob/SMakefile new file mode 100644 index 0000000..0476a15 --- /dev/null +++ b/src/kmk/glob/SMakefile @@ -0,0 +1,67 @@ +# Makefile for standalone distribution of libglob.a (fnmatch, glob). +# Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007 Free Software Foundation, Inc. +# This file is part of GNU Make. +# +# GNU Make is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +# Ultrix 2.2 make doesn't expand the value of VPATH. +VPATH = /glob/ +# This must repeat the value, because configure will remove `VPATH = .'. +srcdir = /glob/ + +CC = sc +CPPFLAGS = +CFLAGS = +MAKE = smake +RM = delete + +# Information determined by configure. +DEFS = Define HAVE_HEADER_STDC Define HAVE_UNISTD_H Define HAVE_STRING_H \ + Define HAVE_DIRENT_H + +# How to invoke ar. +AR = join +ARFLAGS = as + +# How to invoke ranlib. +RANLIB = ; + +.PHONY: all +all: glob.lib + +glob.lib : glob.o fnmatch.o + $(AR) $(ARFLAGS) $@ glob.o fnmatch.o + $(RANLIB) $@ + +# For some reason, Unix make wants the dependencies on the source files. +# Otherwise it refuses to use an implicit rule! +# And, get this: it doesn't work to use $(srcdir)foo.c!! +glob.o: $(srcdir)glob.h $(srcdir)fnmatch.h glob.c +fnmatch.o: $(srcdir)fnmatch.h fnmatch.c + +.c.o: + $(CC) IDir "" \ + $(DEFS) $(CPPFLAGS) $(CFLAGS) $< $(OUTPUT_OPTION) + +.PHONY: clean realclean glob-clean glob-realclean distclean +clean glob-clean: + -$(RM) -f glob.lib *.o core +distclean glob-realclean: clean + -$(RM) -f TAGS tags Makefile config.status config.h config.log +realcean: distclean + +# For inside the C library. +glob.tar glob.tar.Z: + $(MAKE) -C .. $@ diff --git a/src/kmk/glob/configure.bat b/src/kmk/glob/configure.bat new file mode 100644 index 0000000..672d733 --- /dev/null +++ b/src/kmk/glob/configure.bat @@ -0,0 +1,43 @@ +@echo off +rem Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, +rem 2004, 2005, 2006, 2007 Free Software Foundation, Inc. +rem This file is part of GNU Make. +rem +rem GNU Make is free software; you can redistribute it and/or modify it under +rem the terms of the GNU General Public License as published by the Free +rem Software Foundation; either version 3 of the License, or (at your option) +rem any later version. +rem +rem GNU Make is distributed in the hope that it will be useful, but WITHOUT +rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for. +rem more details. +rem +rem You should have received a copy of the GNU General Public License along +rem with this program. If not, see . + +echo Configuring glob for DJGPP +rem This batch file assumes a unix-type "sed" program + +echo # Makefile generated by "configure.bat"> Makefile + +if exist config.sed del config.sed + +echo "s/@srcdir@/./ ">> config.sed +echo "s/@CC@/gcc/ ">> config.sed +echo "s/@CFLAGS@/-O2 -g/ ">> config.sed +echo "s/@CPPFLAGS@/-DHAVE_CONFIG_H -I../ ">> config.sed +echo "s/@AR@/ar/ ">> config.sed +echo "s/@RANLIB@/ranlib/ ">> config.sed +echo "s/@LDFLAGS@// ">> config.sed +echo "s/@DEFS@// ">> config.sed +echo "s/@ALLOCA@// ">> config.sed +echo "s/@LIBS@// ">> config.sed +echo "s/@LIBOBJS@// ">> config.sed +echo "s/^Makefile *:/_Makefile:/ ">> config.sed +echo "s/^config.h *:/_config.h:/ ">> config.sed + +sed -e "s/^\"//" -e "s/\"$//" -e "s/[ ]*$//" config.sed > config2.sed +sed -f config2.sed Makefile.in >> Makefile +del config.sed +del config2.sed diff --git a/src/kmk/glob/fnmatch.c b/src/kmk/glob/fnmatch.c new file mode 100644 index 0000000..b346e10 --- /dev/null +++ b/src/kmk/glob/fnmatch.c @@ -0,0 +1,489 @@ +/* Copyright (C) 1991, 1992, 1993, 1996, 1997, 1998, 1999 Free Software +Foundation, Inc. +This file is part of the GNU C Library. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this library; see the file COPYING.LIB. If not, write to the Free +Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA. */ + +#if HAVE_CONFIG_H +# include +#endif + +/* Enable GNU extensions in fnmatch.h. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +#include +#include +#include + +#if HAVE_STRING_H || defined _LIBC +# include +#else +# include +#endif + +#if defined STDC_HEADERS || defined _LIBC +# include +#endif + +/* For platform which support the ISO C amendement 1 functionality we + support user defined character classes. */ +#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) +/* Solaris 2.5 has a bug: must be included before . */ +# include +# include +#endif + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined _LIBC || !defined __GNU_LIBRARY__ || 1 /* bird: Same as for glob.c, don't want trouble. */ + + +# if defined STDC_HEADERS || !defined isascii +# define ISASCII(c) 1 +# else +# define ISASCII(c) isascii(c) +# endif + +# ifdef isblank +# define ISBLANK(c) (ISASCII (c) && isblank (c)) +# else +# define ISBLANK(c) ((c) == ' ' || (c) == '\t') +# endif +# ifdef isgraph +# define ISGRAPH(c) (ISASCII (c) && isgraph (c)) +# else +# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c)) +# endif + +# define ISPRINT(c) (ISASCII (c) && isprint (c)) +# define ISDIGIT(c) (ISASCII (c) && isdigit (c)) +# define ISALNUM(c) (ISASCII (c) && isalnum (c)) +# define ISALPHA(c) (ISASCII (c) && isalpha (c)) +# define ISCNTRL(c) (ISASCII (c) && iscntrl (c)) +# define ISLOWER(c) (ISASCII (c) && islower (c)) +# define ISPUNCT(c) (ISASCII (c) && ispunct (c)) +# define ISSPACE(c) (ISASCII (c) && isspace (c)) +# define ISUPPER(c) (ISASCII (c) && isupper (c)) +# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c)) + +# define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) + +# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) +/* The GNU C library provides support for user-defined character classes + and the functions from ISO C amendement 1. */ +# ifdef CHARCLASS_NAME_MAX +# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX +# else +/* This shouldn't happen but some implementation might still have this + problem. Use a reasonable default value. */ +# define CHAR_CLASS_MAX_LENGTH 256 +# endif + +# ifdef _LIBC +# define IS_CHAR_CLASS(string) __wctype (string) +# else +# define IS_CHAR_CLASS(string) wctype (string) +# endif +# else +# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ + +# define IS_CHAR_CLASS(string) \ + (STREQ (string, "alpha") || STREQ (string, "upper") \ + || STREQ (string, "lower") || STREQ (string, "digit") \ + || STREQ (string, "alnum") || STREQ (string, "xdigit") \ + || STREQ (string, "space") || STREQ (string, "print") \ + || STREQ (string, "punct") || STREQ (string, "graph") \ + || STREQ (string, "cntrl") || STREQ (string, "blank")) +# endif + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +# if !defined _LIBC && !defined getenv && !defined _MSC_VER +extern char *getenv (); +# endif + +# ifndef errno +extern int errno; +# endif + +/* This function doesn't exist on most systems. */ + +# if !defined HAVE___STRCHRNUL && !defined _LIBC +static char * +__strchrnul (s, c) + const char *s; + int c; +{ + char *result = strchr (s, c); + if (result == NULL) + result = strchr (s, '\0'); + return result; +} +# endif + +# ifndef internal_function +/* Inside GNU libc we mark some function in a special way. In other + environments simply ignore the marking. */ +# define internal_function +# endif + +/* Match STRING against the filename pattern PATTERN, returning zero if + it matches, nonzero if not. */ +static int internal_fnmatch __P ((const char *pattern, const char *string, + int no_leading_period, int flags)) + internal_function; +static int +internal_function +internal_fnmatch (pattern, string, no_leading_period, flags) + const char *pattern; + const char *string; + int no_leading_period; + int flags; +{ + register const char *p = pattern, *n = string; + register unsigned char c; + +/* Note that this evaluates C many times. */ +# ifdef _LIBC +# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c)) +# else +# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c)) +# endif + + while ((c = *p++) != '\0') + { + c = FOLD (c); + + switch (c) + { + case '?': + if (*n == '\0') + return FNM_NOMATCH; + else if (*n == '/' && (flags & FNM_FILE_NAME)) + return FNM_NOMATCH; + else if (*n == '.' && no_leading_period + && (n == string + || (n[-1] == '/' && (flags & FNM_FILE_NAME)))) + return FNM_NOMATCH; + break; + + case '\\': + if (!(flags & FNM_NOESCAPE)) + { + c = *p++; + if (c == '\0') + /* Trailing \ loses. */ + return FNM_NOMATCH; + c = FOLD (c); + } + if (FOLD ((unsigned char) *n) != c) + return FNM_NOMATCH; + break; + + case '*': + if (*n == '.' && no_leading_period + && (n == string + || (n[-1] == '/' && (flags & FNM_FILE_NAME)))) + return FNM_NOMATCH; + + for (c = *p++; c == '?' || c == '*'; c = *p++) + { + if (*n == '/' && (flags & FNM_FILE_NAME)) + /* A slash does not match a wildcard under FNM_FILE_NAME. */ + return FNM_NOMATCH; + else if (c == '?') + { + /* A ? needs to match one character. */ + if (*n == '\0') + /* There isn't another character; no match. */ + return FNM_NOMATCH; + else + /* One character of the string is consumed in matching + this ? wildcard, so *??? won't match if there are + less than three characters. */ + ++n; + } + } + + if (c == '\0') + /* The wildcard(s) is/are the last element of the pattern. + If the name is a file name and contains another slash + this does mean it cannot match. */ + return ((flags & FNM_FILE_NAME) && strchr (n, '/') != NULL + ? FNM_NOMATCH : 0); + else + { + const char *endp; + + endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0'); + + if (c == '[') + { + int flags2 = ((flags & FNM_FILE_NAME) + ? flags : (flags & ~FNM_PERIOD)); + + for (--p; n < endp; ++n) + if (internal_fnmatch (p, n, + (no_leading_period + && (n == string + || (n[-1] == '/' + && (flags + & FNM_FILE_NAME)))), + flags2) + == 0) + return 0; + } + else if (c == '/' && (flags & FNM_FILE_NAME)) + { + while (*n != '\0' && *n != '/') + ++n; + if (*n == '/' + && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD, + flags) == 0)) + return 0; + } + else + { + int flags2 = ((flags & FNM_FILE_NAME) + ? flags : (flags & ~FNM_PERIOD)); + + if (c == '\\' && !(flags & FNM_NOESCAPE)) + c = *p; + c = FOLD (c); + for (--p; n < endp; ++n) + if (FOLD ((unsigned char) *n) == c + && (internal_fnmatch (p, n, + (no_leading_period + && (n == string + || (n[-1] == '/' + && (flags + & FNM_FILE_NAME)))), + flags2) == 0)) + return 0; + } + } + + /* If we come here no match is possible with the wildcard. */ + return FNM_NOMATCH; + + case '[': + { + /* Nonzero if the sense of the character class is inverted. */ + static int posixly_correct; + register int not; + char cold; + + if (posixly_correct == 0) + posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; + + if (*n == '\0') + return FNM_NOMATCH; + + if (*n == '.' && no_leading_period && (n == string + || (n[-1] == '/' + && (flags + & FNM_FILE_NAME)))) + return FNM_NOMATCH; + + if (*n == '/' && (flags & FNM_FILE_NAME)) + /* `/' cannot be matched. */ + return FNM_NOMATCH; + + not = (*p == '!' || (posixly_correct < 0 && *p == '^')); + if (not) + ++p; + + c = *p++; + for (;;) + { + unsigned char fn = FOLD ((unsigned char) *n); + + if (!(flags & FNM_NOESCAPE) && c == '\\') + { + if (*p == '\0') + return FNM_NOMATCH; + c = FOLD ((unsigned char) *p); + ++p; + + if (c == fn) + goto matched; + } + else if (c == '[' && *p == ':') + { + /* Leave room for the null. */ + char str[CHAR_CLASS_MAX_LENGTH + 1]; + size_t c1 = 0; +# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) + wctype_t wt; +# endif + const char *startp = p; + + for (;;) + { + if (c1 == CHAR_CLASS_MAX_LENGTH) + /* The name is too long and therefore the pattern + is ill-formed. */ + return FNM_NOMATCH; + + c = *++p; + if (c == ':' && p[1] == ']') + { + p += 2; + break; + } + if (c < 'a' || c >= 'z') + { + /* This cannot possibly be a character class name. + Match it as a normal range. */ + p = startp; + c = '['; + goto normal_bracket; + } + str[c1++] = c; + } + str[c1] = '\0'; + +# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) + wt = IS_CHAR_CLASS (str); + if (wt == 0) + /* Invalid character class name. */ + return FNM_NOMATCH; + + if (__iswctype (__btowc ((unsigned char) *n), wt)) + goto matched; +# else + if ((STREQ (str, "alnum") && ISALNUM ((unsigned char) *n)) + || (STREQ (str, "alpha") && ISALPHA ((unsigned char) *n)) + || (STREQ (str, "blank") && ISBLANK ((unsigned char) *n)) + || (STREQ (str, "cntrl") && ISCNTRL ((unsigned char) *n)) + || (STREQ (str, "digit") && ISDIGIT ((unsigned char) *n)) + || (STREQ (str, "graph") && ISGRAPH ((unsigned char) *n)) + || (STREQ (str, "lower") && ISLOWER ((unsigned char) *n)) + || (STREQ (str, "print") && ISPRINT ((unsigned char) *n)) + || (STREQ (str, "punct") && ISPUNCT ((unsigned char) *n)) + || (STREQ (str, "space") && ISSPACE ((unsigned char) *n)) + || (STREQ (str, "upper") && ISUPPER ((unsigned char) *n)) + || (STREQ (str, "xdigit") && ISXDIGIT ((unsigned char) *n))) + goto matched; +# endif + } + else if (c == '\0') + /* [ (unterminated) loses. */ + return FNM_NOMATCH; + else + { + normal_bracket: + if (FOLD (c) == fn) + goto matched; + + cold = c; + c = *p++; + + if (c == '-' && *p != ']') + { + /* It is a range. */ + unsigned char cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return FNM_NOMATCH; + + if (cold <= fn && fn <= FOLD (cend)) + goto matched; + + c = *p++; + } + } + + if (c == ']') + break; + } + + if (!not) + return FNM_NOMATCH; + break; + + matched: + /* Skip the rest of the [...] that already matched. */ + while (c != ']') + { + if (c == '\0') + /* [... (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + if (!(flags & FNM_NOESCAPE) && c == '\\') + { + if (*p == '\0') + return FNM_NOMATCH; + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } + else if (c == '[' && *p == ':') + { + do + if (*++p == '\0') + return FNM_NOMATCH; + while (*p != ':' || p[1] == ']'); + p += 2; + c = *p; + } + } + if (not) + return FNM_NOMATCH; + } + break; + + default: + if (c != FOLD ((unsigned char) *n)) + return FNM_NOMATCH; + } + + ++n; + } + + if (*n == '\0') + return 0; + + if ((flags & FNM_LEADING_DIR) && *n == '/') + /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ + return 0; + + return FNM_NOMATCH; + +# undef FOLD +} + + +int +fnmatch (pattern, string, flags) + const char *pattern; + const char *string; + int flags; +{ + return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags); +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/src/kmk/glob/fnmatch.h b/src/kmk/glob/fnmatch.h new file mode 100644 index 0000000..a788c8e --- /dev/null +++ b/src/kmk/glob/fnmatch.h @@ -0,0 +1,85 @@ +/* Copyright (C) 1991, 1992, 1993, 1996, 1997, 1998, 1999 Free Software +Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this library; see the file COPYING.LIB. If not, write to the Free +Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA. */ + +#ifndef _FNMATCH_H +#define _FNMATCH_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32 +# if !defined __GLIBC__ +# undef __P +# define __P(protos) protos +# endif +#else /* Not C++ or ANSI C. */ +# undef __P +# define __P(protos) () +/* We can get away without defining `const' here only because in this file + it is used only inside the prototype for `fnmatch', which is elided in + non-ANSI C where `const' is problematical. */ +#endif /* C++ or ANSI C. */ + +#ifndef const +# if (defined __STDC__ && __STDC__) || defined __cplusplus || defined WINDOWS32 +# define __const const +# else +# define __const +# endif +#endif + +/* We #undef these before defining them because some losing systems + (HP-UX A.08.07 for example) define these in . */ +#undef FNM_PATHNAME +#undef FNM_NOESCAPE +#undef FNM_PERIOD + +/* Bits set in the FLAGS argument to `fnmatch'. */ +#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ +#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ +#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ + +#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE +# define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ +# define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ +# define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +#endif + +/* Value returned by `fnmatch' if STRING does not match PATTERN. */ +#define FNM_NOMATCH 1 + +/* This value is returned if the implementation does not support + `fnmatch'. Since this is not the case here it will never be + returned but the conformance test suites still require the symbol + to be defined. */ +#ifdef _XOPEN_SOURCE +# define FNM_NOSYS (-1) +#endif + +/* Match NAME against the filename pattern PATTERN, + returning zero if it matches, FNM_NOMATCH if not. */ +extern int fnmatch __P ((__const char *__pattern, __const char *__name, + int __flags)); + +#ifdef __cplusplus +} +#endif + +#endif /* fnmatch.h */ diff --git a/src/kmk/glob/glob.c b/src/kmk/glob/glob.c new file mode 100644 index 0000000..98827cd --- /dev/null +++ b/src/kmk/glob/glob.c @@ -0,0 +1,1463 @@ +/* Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999 Free +Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this library; see the file COPYING.LIB. If not, write to the Free +Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA. */ + +/* AIX requires this to be the first thing in the file. */ +#if defined _AIX && !defined __GNUC__ + #pragma alloca +#endif + +#ifdef HAVE_CONFIG_H +# include +#endif + +/* Enable GNU extensions in glob.h. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +#include +#include +#include + +/* Outcomment the following line for production quality code. */ +/* #define NDEBUG 1 */ +#include + +#include /* Needed on stupid SunOS for assert. */ + + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GLOB_INTERFACE_VERSION 1 +#if 0 /* bird: Apparently this causes trouble for some debian builds. */ +#if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1 +# include +# if _GNU_GLOB_INTERFACE_VERSION == GLOB_INTERFACE_VERSION +# define ELIDE_CODE +# endif +#endif +#endif + +#ifndef ELIDE_CODE + +#if defined STDC_HEADERS || defined __GNU_LIBRARY__ +# include +#endif + +#if defined HAVE_UNISTD_H || defined _LIBC +# include +# ifndef POSIX +# ifdef _POSIX_VERSION +# define POSIX +# endif +# endif +#endif + +#if !defined _AMIGA && !defined VMS && !defined WINDOWS32 +# include +#endif + +#if !defined __GNU_LIBRARY__ && !defined STDC_HEADERS +extern int errno; +#endif +#ifndef __set_errno +# define __set_errno(val) errno = (val) +#endif + +#ifndef NULL +# define NULL 0 +#endif + + +#if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__ +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +# ifdef HAVE_VMSDIR_H +# include "vmsdir.h" +# endif /* HAVE_VMSDIR_H */ +#endif + + +/* In GNU systems, defines this macro for us. */ +#ifdef _D_NAMLEN +# undef NAMLEN +# define NAMLEN(d) _D_NAMLEN(d) +#endif + +/* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available + if the `d_type' member for `struct dirent' is available. */ +#ifdef _DIRENT_HAVE_D_TYPE +# define HAVE_D_TYPE 1 +#endif + + +#if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__ +/* Posix does not require that the d_ino field be present, and some + systems do not provide it. */ +# define REAL_DIR_ENTRY(dp) 1 +#else +# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) +#endif /* POSIX */ + +#if defined STDC_HEADERS || defined __GNU_LIBRARY__ +# include +# include +# define ANSI_STRING +#else /* No standard headers. */ + +extern char *getenv (); + +# ifdef HAVE_STRING_H +# include +# define ANSI_STRING +# else +# include +# endif +# ifdef HAVE_MEMORY_H +# include +# endif + +extern char *malloc (), *realloc (); +extern void free (); + +extern void qsort (); +extern void abort (), exit (); + +#endif /* Standard headers. */ + +#ifndef ANSI_STRING + +# ifndef bzero +extern void bzero (); +# endif +# ifndef bcopy +extern void bcopy (); +# endif + +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# define strrchr rindex +/* memset is only used for zero here, but let's be paranoid. */ +# define memset(s, better_be_zero, n) \ + ((void) ((better_be_zero) == 0 ? (bzero((s), (n)), 0) : (abort(), 0))) +#endif /* Not ANSI_STRING. */ + +#if !defined HAVE_STRCOLL && !defined _LIBC +# define strcoll strcmp +#endif + +#if !defined HAVE_MEMPCPY && __GLIBC__ - 0 == 2 && __GLIBC_MINOR__ >= 1 +# define HAVE_MEMPCPY 1 +#if 0 /* bird: This messes with the electric.c heap (linux/amd64). Probably missing prototype, so int return. */ +# undef mempcpy +# define mempcpy(Dest, Src, Len) __mempcpy (Dest, Src, Len) +#endif +#endif + +#if !defined __GNU_LIBRARY__ && !defined __DJGPP__ && !defined ELECTRIC_HEAP && !defined __APPLE__ /* bird (last two) */ +# ifdef __GNUC__ +__inline +# endif +# ifndef __SASC +# ifdef WINDOWS32 +# include +static void * +my_realloc (void *p, unsigned int n) +# else +static char * +my_realloc (p, n) + char *p; + unsigned int n; +# endif +{ + /* These casts are the for sake of the broken Ultrix compiler, + which warns of illegal pointer combinations otherwise. */ + if (p == NULL) + return (char *) malloc (n); + return (char *) realloc (p, n); +} +# define realloc my_realloc +# endif /* __SASC */ +#endif /* __GNU_LIBRARY__ || __DJGPP__ */ + + +#if !defined __alloca /*&& !defined __GNU_LIBRARY__ - bird: unresolved __alloca symbol if skipping this for gnu libc. duh. */ + +# ifdef __GNUC__ +# undef alloca +# define alloca(n) __builtin_alloca (n) +# else /* Not GCC. */ +# ifdef HAVE_ALLOCA_H +# include +# else /* Not HAVE_ALLOCA_H. */ +# ifndef _AIX +# ifdef WINDOWS32 +# include +# else +extern char *alloca (); +# endif /* WINDOWS32 */ +# endif /* Not _AIX. */ +# endif /* sparc or HAVE_ALLOCA_H. */ +# endif /* Not GCC. */ + +# define __alloca alloca + +#endif + +#if 1 /*bird: sigh. ndef __GNU_LIBRARY__*/ +# define __stat stat +# ifdef STAT_MACROS_BROKEN +# undef S_ISDIR +# endif +# ifndef S_ISDIR +# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +# endif +#endif + +#ifdef _LIBC +# ifdef KMK +# error "_LIBC better not be defined!" +# endif +# undef strdup +# define strdup(str) __strdup (str) +# define sysconf(id) __sysconf (id) +# define closedir(dir) __closedir (dir) +# define opendir(name) __opendir (name) +# define readdir(str) __readdir (str) +# define getpwnam_r(name, bufp, buf, len, res) \ + __getpwnam_r (name, bufp, buf, len, res) +# ifndef __stat +# define __stat(fname, buf) __xstat (_STAT_VER, fname, buf) +# endif +#endif + +#if !(defined STDC_HEADERS || defined __GNU_LIBRARY__) +# undef size_t +# define size_t unsigned int +#endif + +/* Some system header files erroneously define these. + We want our own definitions from to take precedence. */ +#ifndef __GNU_LIBRARY__ +# undef FNM_PATHNAME +# undef FNM_NOESCAPE +# undef FNM_PERIOD +#endif +#include + +/* Some system header files erroneously define these. + We want our own definitions from to take precedence. */ +#ifndef __GNU_LIBRARY__ +# undef GLOB_ERR +# undef GLOB_MARK +# undef GLOB_NOSORT +# undef GLOB_DOOFFS +# undef GLOB_NOCHECK +# undef GLOB_APPEND +# undef GLOB_NOESCAPE +# undef GLOB_PERIOD +#endif +#include + +#ifdef HAVE_GETLOGIN_R +extern int getlogin_r __P ((char *, size_t)); +#else +extern char *getlogin __P ((void)); +#endif + +static +#if __GNUC__ - 0 >= 2 +inline +#endif +const char *next_brace_sub __P ((const char *begin)); +static int glob_in_dir __P ((const char *pattern, const char *directory, + int flags, + int (*errfunc) (const char *, int), + glob_t *pglob)); +static int prefix_array __P ((const char *prefix, char **array, size_t n)); +static int collated_compare __P ((const __ptr_t, const __ptr_t)); + +#if !defined _LIBC || !defined NO_GLOB_PATTERN_P +int __glob_pattern_p __P ((const char *pattern, int quote)); +#endif + +/* Find the end of the sub-pattern in a brace expression. We define + this as an inline function if the compiler permits. */ +static +#if __GNUC__ - 0 >= 2 +inline +#endif +const char * +next_brace_sub (begin) + const char *begin; +{ + unsigned int depth = 0; + const char *cp = begin; + + while (1) + { + if (depth == 0) + { + if (*cp != ',' && *cp != '}' && *cp != '\0') + { + if (*cp == '{') + ++depth; + ++cp; + continue; + } + } + else + { + while (*cp != '\0' && (*cp != '}' || depth > 0)) + { + if (*cp == '}') + --depth; + ++cp; + } + if (*cp == '\0') + /* An incorrectly terminated brace expression. */ + return NULL; + + continue; + } + break; + } + + return cp; +} + +/* Do glob searching for PATTERN, placing results in PGLOB. + The bits defined above may be set in FLAGS. + If a directory cannot be opened or read and ERRFUNC is not nil, + it is called with the pathname that caused the error, and the + `errno' value from the failing call; if it returns non-zero + `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored. + If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned. + Otherwise, `glob' returns zero. */ +int +glob (pattern, flags, errfunc, pglob) + const char *pattern; + int flags; + int (*errfunc) __P ((const char *, int)); + glob_t *pglob; +{ + const char *filename; + const char *dirname; + size_t dirlen; + int status; + __size_t oldcount; /* bird: correct type. */ + + if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0) + { + __set_errno (EINVAL); + return -1; + } + + /* POSIX requires all slashes to be matched. This means that with + a trailing slash we must match only directories. */ + if (pattern[0] && pattern[strlen (pattern) - 1] == '/') + flags |= GLOB_ONLYDIR; + + if (flags & GLOB_BRACE) + { + const char *begin = strchr (pattern, '{'); + if (begin != NULL) + { + /* Allocate working buffer large enough for our work. Note that + we have at least an opening and closing brace. */ + size_t firstc; /* bird: correct type. */ + char *alt_start; + const char *p; + const char *next; + const char *rest; + size_t rest_len; +#ifdef __GNUC__ + char onealt[strlen (pattern) - 1]; +#else + char *onealt = (char *) malloc (strlen (pattern) - 1); + if (onealt == NULL) + { + if (!(flags & GLOB_APPEND)) + globfree (pglob); + return GLOB_NOSPACE; + } +#endif + + /* We know the prefix for all sub-patterns. */ +#ifdef HAVE_MEMPCPY + alt_start = mempcpy (onealt, pattern, begin - pattern); +#else + memcpy (onealt, pattern, begin - pattern); + alt_start = &onealt[begin - pattern]; +#endif + + /* Find the first sub-pattern and at the same time find the + rest after the closing brace. */ + next = next_brace_sub (begin + 1); + if (next == NULL) + { + /* It is an illegal expression. */ +#ifndef __GNUC__ + free (onealt); +#endif + return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob); + } + + /* Now find the end of the whole brace expression. */ + rest = next; + while (*rest != '}') + { + rest = next_brace_sub (rest + 1); + if (rest == NULL) + { + /* It is an illegal expression. */ +#ifndef __GNUC__ + free (onealt); +#endif + return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob); + } + } + /* Please note that we now can be sure the brace expression + is well-formed. */ + rest_len = strlen (++rest) + 1; + + /* We have a brace expression. BEGIN points to the opening {, + NEXT points past the terminator of the first element, and END + points past the final }. We will accumulate result names from + recursive runs for each brace alternative in the buffer using + GLOB_APPEND. */ + + if (!(flags & GLOB_APPEND)) + { + /* This call is to set a new vector, so clear out the + vector so we can append to it. */ + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + } + firstc = pglob->gl_pathc; + + p = begin + 1; + while (1) + { + int result; + + /* Construct the new glob expression. */ +#ifdef HAVE_MEMPCPY + mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len); +#else + memcpy (alt_start, p, next - p); + memcpy (&alt_start[next - p], rest, rest_len); +#endif + + result = glob (onealt, + ((flags & ~(GLOB_NOCHECK|GLOB_NOMAGIC)) + | GLOB_APPEND), errfunc, pglob); + + /* If we got an error, return it. */ + if (result && result != GLOB_NOMATCH) + { +#ifndef __GNUC__ + free (onealt); +#endif + if (!(flags & GLOB_APPEND)) + globfree (pglob); + return result; + } + + if (*next == '}') + /* We saw the last entry. */ + break; + + p = next + 1; + next = next_brace_sub (p); + assert (next != NULL); + } + +#ifndef __GNUC__ + free (onealt); +#endif + + if (pglob->gl_pathc != firstc) + /* We found some entries. */ + return 0; + else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) + return GLOB_NOMATCH; + } + } + + /* Find the filename. */ + filename = strrchr (pattern, '/'); +#if defined __MSDOS__ || defined WINDOWS32 + /* The case of "d:pattern". Since `:' is not allowed in + file names, we can safely assume that wherever it + happens in pattern, it signals the filename part. This + is so we could some day support patterns like "[a-z]:foo". */ + if (filename == NULL) + filename = strchr (pattern, ':'); +#endif /* __MSDOS__ || WINDOWS32 */ + if (filename == NULL) + { + /* This can mean two things: a simple name or "~name". The later + case is nothing but a notation for a directory. */ + if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~') + { + dirname = pattern; + dirlen = strlen (pattern); + + /* Set FILENAME to NULL as a special flag. This is ugly but + other solutions would require much more code. We test for + this special case below. */ + filename = NULL; + } + else + { + filename = pattern; +#ifdef _AMIGA + dirname = ""; +#else + dirname = "."; +#endif + dirlen = 0; + } + } + else if (filename == pattern) + { + /* "/pattern". */ + dirname = "/"; + dirlen = 1; + ++filename; + } + else + { + char *newp; + dirlen = filename - pattern; +#if defined __MSDOS__ || defined WINDOWS32 + if (*filename == ':' + || (filename > pattern + 1 && filename[-1] == ':')) + { + char *drive_spec; + + ++dirlen; + drive_spec = (char *) __alloca (dirlen + 1); +#ifdef HAVE_MEMPCPY + *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0'; +#else + memcpy (drive_spec, pattern, dirlen); + drive_spec[dirlen] = '\0'; +#endif + /* For now, disallow wildcards in the drive spec, to + prevent infinite recursion in glob. */ + if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE))) + return GLOB_NOMATCH; + /* If this is "d:pattern", we need to copy `:' to DIRNAME + as well. If it's "d:/pattern", don't remove the slash + from "d:/", since "d:" and "d:/" are not the same.*/ + } +#endif + newp = (char *) __alloca (dirlen + 1); +#ifdef HAVE_MEMPCPY + *((char *) mempcpy (newp, pattern, dirlen)) = '\0'; +#else + memcpy (newp, pattern, dirlen); + newp[dirlen] = '\0'; +#endif + dirname = newp; + ++filename; + + if (filename[0] == '\0' +#if defined __MSDOS__ || defined WINDOWS32 + && dirname[dirlen - 1] != ':' + && (dirlen < 3 || dirname[dirlen - 2] != ':' + || dirname[dirlen - 1] != '/') +#endif + && dirlen > 1) + /* "pattern/". Expand "pattern", appending slashes. */ + { + int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob); + if (val == 0) + pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK) + | (flags & GLOB_MARK)); + return val; + } + } + + if (!(flags & GLOB_APPEND)) + { + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + } + + oldcount = pglob->gl_pathc; + +#ifndef VMS + if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~') + { + if (dirname[1] == '\0' || dirname[1] == '/') + { + /* Look up home directory. */ +#ifdef VMS +/* This isn't obvious, RTLs of DECC and VAXC know about "HOME" */ + const char *home_dir = getenv ("SYS$LOGIN"); +#else + const char *home_dir = getenv ("HOME"); +#endif +# ifdef _AMIGA + if (home_dir == NULL || home_dir[0] == '\0') + home_dir = "SYS:"; +# else +# ifdef WINDOWS32 + if (home_dir == NULL || home_dir[0] == '\0') + home_dir = "c:/users/default"; /* poor default */ +# else +# ifdef VMS +/* Again, this isn't obvious, if "HOME" isn't known "SYS$LOGIN" should be set */ + if (home_dir == NULL || home_dir[0] == '\0') + home_dir = "SYS$DISK:[]"; +# else + if (home_dir == NULL || home_dir[0] == '\0') + { + int success; + char *name; +# if defined HAVE_GETLOGIN_R || defined _LIBC + size_t buflen = sysconf (_SC_LOGIN_NAME_MAX) + 1; + + if (buflen == 0) + /* `sysconf' does not support _SC_LOGIN_NAME_MAX. Try + a moderate value. */ + buflen = 20; + name = (char *) __alloca (buflen); + + success = getlogin_r (name, buflen) >= 0; +# else + success = (name = getlogin ()) != NULL; +# endif + if (success) + { + struct passwd *p; +# if defined HAVE_GETPWNAM_R || defined _LIBC + size_t pwbuflen = sysconf (_SC_GETPW_R_SIZE_MAX); + char *pwtmpbuf; + struct passwd pwbuf; + int save = errno; + + if (pwbuflen == -1) + /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. + Try a moderate value. */ + pwbuflen = 1024; + pwtmpbuf = (char *) __alloca (pwbuflen); + + while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p) + != 0) + { + if (errno != ERANGE) + { + p = NULL; + break; + } + pwbuflen *= 2; + pwtmpbuf = (char *) __alloca (pwbuflen); + __set_errno (save); + } +# else + p = getpwnam (name); +# endif + if (p != NULL) + home_dir = p->pw_dir; + } + } + if (home_dir == NULL || home_dir[0] == '\0') + { + if (flags & GLOB_TILDE_CHECK) + return GLOB_NOMATCH; + else + home_dir = "~"; /* No luck. */ + } +# endif /* VMS */ +# endif /* WINDOWS32 */ +# endif + /* Now construct the full directory. */ + if (dirname[1] == '\0') + dirname = home_dir; + else + { + char *newp; + size_t home_len = strlen (home_dir); + newp = (char *) __alloca (home_len + dirlen); +# ifdef HAVE_MEMPCPY + mempcpy (mempcpy (newp, home_dir, home_len), + &dirname[1], dirlen); +# else + memcpy (newp, home_dir, home_len); + memcpy (&newp[home_len], &dirname[1], dirlen); +# endif + dirname = newp; + } + } +# if !defined _AMIGA && !defined WINDOWS32 && !defined VMS + else + { + char *end_name = strchr (dirname, '/'); + const char *user_name; + const char *home_dir; + + if (end_name == NULL) + user_name = dirname + 1; + else + { + char *newp; + newp = (char *) __alloca (end_name - dirname); +# ifdef HAVE_MEMPCPY + *((char *) mempcpy (newp, dirname + 1, end_name - dirname)) + = '\0'; +# else + memcpy (newp, dirname + 1, end_name - dirname); + newp[end_name - dirname - 1] = '\0'; +# endif + user_name = newp; + } + + /* Look up specific user's home directory. */ + { + struct passwd *p; +# if defined HAVE_GETPWNAM_R || defined _LIBC + size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); + char *pwtmpbuf; + struct passwd pwbuf; + int save = errno; + + if (buflen == -1) + /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a + moderate value. */ + buflen = 1024; + pwtmpbuf = (char *) __alloca (buflen); + + while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0) + { + if (errno != ERANGE) + { + p = NULL; + break; + } + buflen *= 2; + pwtmpbuf = __alloca (buflen); + __set_errno (save); + } +# else + p = getpwnam (user_name); +# endif + if (p != NULL) + home_dir = p->pw_dir; + else + home_dir = NULL; + } + /* If we found a home directory use this. */ + if (home_dir != NULL) + { + char *newp; + size_t home_len = strlen (home_dir); + size_t rest_len = end_name == NULL ? 0 : strlen (end_name); + newp = (char *) __alloca (home_len + rest_len + 1); +# ifdef HAVE_MEMPCPY + *((char *) mempcpy (mempcpy (newp, home_dir, home_len), + end_name, rest_len)) = '\0'; +# else + memcpy (newp, home_dir, home_len); + memcpy (&newp[home_len], end_name, rest_len); + newp[home_len + rest_len] = '\0'; +# endif + dirname = newp; + } + else + if (flags & GLOB_TILDE_CHECK) + /* We have to regard it as an error if we cannot find the + home directory. */ + return GLOB_NOMATCH; + } +# endif /* Not Amiga && not WINDOWS32 && not VMS. */ + } +#endif /* Not VMS. */ + + /* Now test whether we looked for "~" or "~NAME". In this case we + can give the answer now. */ + if (filename == NULL) + { + struct stat st; + + /* Return the directory if we don't check for error or if it exists. */ + if ((flags & GLOB_NOCHECK) +#ifdef KMK + || (flags & GLOB_ALTDIRFUNC + ? (*pglob->gl_isdir) (dirname) + : __stat (dirname, &st) == 0 && S_ISDIR (st.st_mode)) +#else + || (((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_stat) (dirname, &st) + : __stat (dirname, &st)) == 0 + && S_ISDIR (st.st_mode)) +#endif + ) + { + pglob->gl_pathv + = (char **) realloc (pglob->gl_pathv, + (pglob->gl_pathc + + ((flags & GLOB_DOOFFS) ? + pglob->gl_offs : 0) + + 1 + 1) * + sizeof (char *)); + if (pglob->gl_pathv == NULL) + return GLOB_NOSPACE; + + if (flags & GLOB_DOOFFS) + while (pglob->gl_pathc < pglob->gl_offs) + pglob->gl_pathv[pglob->gl_pathc++] = NULL; + +#if defined HAVE_STRDUP || defined _LIBC + pglob->gl_pathv[pglob->gl_pathc] = strdup (dirname); +#else + { + size_t len = strlen (dirname) + 1; + char *dircopy = malloc (len); + if (dircopy != NULL) + pglob->gl_pathv[pglob->gl_pathc] = memcpy (dircopy, dirname, + len); + } +#endif + if (pglob->gl_pathv[pglob->gl_pathc] == NULL) + { + free (pglob->gl_pathv); + return GLOB_NOSPACE; + } + pglob->gl_pathv[++pglob->gl_pathc] = NULL; + pglob->gl_flags = flags; + + return 0; + } + + /* Not found. */ + return GLOB_NOMATCH; + } + + if (__glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE))) + { + /* The directory name contains metacharacters, so we + have to glob for the directory, and then glob for + the pattern in each directory found. */ + glob_t dirs; + register __size_t i; /* bird: correct type. */ + + status = glob (dirname, + ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE)) + | GLOB_NOSORT | GLOB_ONLYDIR), + errfunc, &dirs); + if (status != 0) + return status; + + /* We have successfully globbed the preceding directory name. + For each name we found, call glob_in_dir on it and FILENAME, + appending the results to PGLOB. */ + for (i = 0; i < dirs.gl_pathc; ++i) + { + int old_pathc; + +#ifdef SHELL + { + /* Make globbing interruptible in the bash shell. */ + extern int interrupt_state; + + if (interrupt_state) + { + globfree (&dirs); + globfree (&files); + return GLOB_ABORTED; + } + } +#endif /* SHELL. */ + + old_pathc = pglob->gl_pathc; + status = glob_in_dir (filename, dirs.gl_pathv[i], + ((flags | GLOB_APPEND) + & ~(GLOB_NOCHECK | GLOB_ERR)), + errfunc, pglob); + if (status == GLOB_NOMATCH) + /* No matches in this directory. Try the next. */ + continue; + + if (status != 0) + { + globfree (&dirs); + globfree (pglob); + return status; + } + + /* Stick the directory on the front of each name. */ + if (prefix_array (dirs.gl_pathv[i], + &pglob->gl_pathv[old_pathc], + pglob->gl_pathc - old_pathc)) + { + globfree (&dirs); + globfree (pglob); + return GLOB_NOSPACE; + } + } + + flags |= GLOB_MAGCHAR; + + /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls. + But if we have not found any matching entry and thie GLOB_NOCHECK + flag was set we must return the list consisting of the disrectory + names followed by the filename. */ + if (pglob->gl_pathc == oldcount) + { + /* No matches. */ + if (flags & GLOB_NOCHECK) + { + size_t filename_len = strlen (filename) + 1; + char **new_pathv; + struct stat st; + + /* This is an pessimistic guess about the size. */ + pglob->gl_pathv + = (char **) realloc (pglob->gl_pathv, + (pglob->gl_pathc + + ((flags & GLOB_DOOFFS) ? + pglob->gl_offs : 0) + + dirs.gl_pathc + 1) * + sizeof (char *)); + if (pglob->gl_pathv == NULL) + { + globfree (&dirs); + return GLOB_NOSPACE; + } + + if (flags & GLOB_DOOFFS) + while (pglob->gl_pathc < pglob->gl_offs) + pglob->gl_pathv[pglob->gl_pathc++] = NULL; + + for (i = 0; i < dirs.gl_pathc; ++i) + { + const char *dir = dirs.gl_pathv[i]; + size_t dir_len = strlen (dir); + + /* First check whether this really is a directory. */ +#ifdef KMK + if (flags & GLOB_ALTDIRFUNC + ? !pglob->gl_isdir (dir) + : __stat (dir, &st) != 0 || !S_ISDIR (st.st_mode)) +#else + if (((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_stat) (dir, &st) : __stat (dir, &st)) != 0 + || !S_ISDIR (st.st_mode)) +#endif + /* No directory, ignore this entry. */ + continue; + + pglob->gl_pathv[pglob->gl_pathc] = malloc (dir_len + 1 + + filename_len); + if (pglob->gl_pathv[pglob->gl_pathc] == NULL) + { + globfree (&dirs); + globfree (pglob); + return GLOB_NOSPACE; + } + +#ifdef HAVE_MEMPCPY + mempcpy (mempcpy (mempcpy (pglob->gl_pathv[pglob->gl_pathc], + dir, dir_len), + "/", 1), + filename, filename_len); +#else + memcpy (pglob->gl_pathv[pglob->gl_pathc], dir, dir_len); + pglob->gl_pathv[pglob->gl_pathc][dir_len] = '/'; + memcpy (&pglob->gl_pathv[pglob->gl_pathc][dir_len + 1], + filename, filename_len); +#endif + ++pglob->gl_pathc; + } + + pglob->gl_pathv[pglob->gl_pathc] = NULL; + pglob->gl_flags = flags; + + /* Now we know how large the gl_pathv vector must be. */ + new_pathv = (char **) realloc (pglob->gl_pathv, + ((pglob->gl_pathc + 1) + * sizeof (char *))); + if (new_pathv != NULL) + pglob->gl_pathv = new_pathv; + } + else + return GLOB_NOMATCH; + } + + globfree (&dirs); + } + else + { + status = glob_in_dir (filename, dirname, flags, errfunc, pglob); + if (status != 0) + return status; + + if (dirlen > 0) + { + /* Stick the directory on the front of each name. */ + __size_t ignore = oldcount; /* bird: correct type. */ + + if ((flags & GLOB_DOOFFS) && ignore < pglob->gl_offs) + ignore = pglob->gl_offs; + + if (prefix_array (dirname, + &pglob->gl_pathv[ignore], + pglob->gl_pathc - ignore)) + { + globfree (pglob); + return GLOB_NOSPACE; + } + } + } + + if (flags & GLOB_MARK) + { + /* Append slashes to directory names. */ + __size_t i; /* bird: correct type. */ + struct stat st; + for (i = oldcount; i < pglob->gl_pathc; ++i) +#ifdef KMK + if (flags & GLOB_ALTDIRFUNC + ? pglob->gl_isdir (pglob->gl_pathv[i]) + : __stat (pglob->gl_pathv[i], &st) == 0 && S_ISDIR (st.st_mode) ) +#else + if (((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_stat) (pglob->gl_pathv[i], &st) + : __stat (pglob->gl_pathv[i], &st)) == 0 + && S_ISDIR (st.st_mode)) +#endif + { + size_t len = strlen (pglob->gl_pathv[i]) + 2; + char *new = realloc (pglob->gl_pathv[i], len); + if (new == NULL) + { + globfree (pglob); + return GLOB_NOSPACE; + } + strcpy (&new[len - 2], "/"); + pglob->gl_pathv[i] = new; + } + } + + if (!(flags & GLOB_NOSORT)) + { + /* Sort the vector. */ + int non_sort = oldcount; + + if ((flags & GLOB_DOOFFS) && pglob->gl_offs > oldcount) + non_sort = pglob->gl_offs; + + qsort ((__ptr_t) &pglob->gl_pathv[non_sort], + pglob->gl_pathc - non_sort, + sizeof (char *), collated_compare); + } + + return 0; +} + + +/* Free storage allocated in PGLOB by a previous `glob' call. */ +void +globfree (pglob) + register glob_t *pglob; +{ + if (pglob->gl_pathv != NULL) + { + register __size_t i; /* bird: correct type */ + for (i = 0; i < pglob->gl_pathc; ++i) + if (pglob->gl_pathv[i] != NULL) + free ((__ptr_t) pglob->gl_pathv[i]); + free ((__ptr_t) pglob->gl_pathv); + } +} + + +/* Do a collated comparison of A and B. */ +static int +collated_compare (a, b) + const __ptr_t a; + const __ptr_t b; +{ + const char *const s1 = *(const char *const * const) a; + const char *const s2 = *(const char *const * const) b; + + if (s1 == s2) + return 0; + if (s1 == NULL) + return 1; + if (s2 == NULL) + return -1; + return strcoll (s1, s2); +} + + +/* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's + elements in place. Return nonzero if out of memory, zero if successful. + A slash is inserted between DIRNAME and each elt of ARRAY, + unless DIRNAME is just "/". Each old element of ARRAY is freed. */ +static int +prefix_array (dirname, array, n) + const char *dirname; + char **array; + size_t n; +{ + register size_t i; + size_t dirlen = strlen (dirname); +#if defined __MSDOS__ || defined WINDOWS32 + int sep_char = '/'; +# define DIRSEP_CHAR sep_char +#else +# define DIRSEP_CHAR '/' +#endif + + if (dirlen == 1 && dirname[0] == '/') + /* DIRNAME is just "/", so normal prepending would get us "//foo". + We want "/foo" instead, so don't prepend any chars from DIRNAME. */ + dirlen = 0; +#if defined __MSDOS__ || defined WINDOWS32 + else if (dirlen > 1) + { + if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':') + /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */ + --dirlen; + else if (dirname[dirlen - 1] == ':') + { + /* DIRNAME is "d:". Use `:' instead of `/'. */ + --dirlen; + sep_char = ':'; + } + } +#endif + + for (i = 0; i < n; ++i) + { + size_t eltlen = strlen (array[i]) + 1; + char *new = (char *) malloc (dirlen + 1 + eltlen); + if (new == NULL) + { + while (i > 0) + free ((__ptr_t) array[--i]); + return 1; + } + +#ifdef HAVE_MEMPCPY + { + char *endp = (char *) mempcpy (new, dirname, dirlen); + *endp++ = DIRSEP_CHAR; + mempcpy (endp, array[i], eltlen); + } +#else + memcpy (new, dirname, dirlen); + new[dirlen] = DIRSEP_CHAR; + memcpy (&new[dirlen + 1], array[i], eltlen); +#endif + free ((__ptr_t) array[i]); + array[i] = new; + } + + return 0; +} + + +/* We must not compile this function twice. */ +#if !defined _LIBC || !defined NO_GLOB_PATTERN_P +/* Return nonzero if PATTERN contains any metacharacters. + Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ +int +__glob_pattern_p (pattern, quote) + const char *pattern; + int quote; +{ + register const char *p; + int open = 0; + + for (p = pattern; *p != '\0'; ++p) + switch (*p) + { + case '?': + case '*': + return 1; + + case '\\': + if (quote && p[1] != '\0') + ++p; + break; + + case '[': + open = 1; + break; + + case ']': + if (open) + return 1; + break; + } + + return 0; +} +# ifdef _LIBC +weak_alias (__glob_pattern_p, glob_pattern_p) +# endif +#endif + + +/* Like `glob', but PATTERN is a final pathname component, + and matches are searched for in DIRECTORY. + The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done. + The GLOB_APPEND flag is assumed to be set (always appends). */ +static int +glob_in_dir (pattern, directory, flags, errfunc, pglob) + const char *pattern; + const char *directory; + int flags; + int (*errfunc) __P ((const char *, int)); + glob_t *pglob; +{ + __ptr_t stream = NULL; + + struct globlink + { + struct globlink *next; + char *name; + }; + struct globlink *names = NULL; + size_t nfound; + int meta; + int save; + +#ifdef VMS + if (*directory == 0) + directory = "[]"; +#endif + meta = __glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE)); + if (meta == 0) + { + if (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)) + /* We need not do any tests. The PATTERN contains no meta + characters and we must not return an error therefore the + result will always contain exactly one name. */ + flags |= GLOB_NOCHECK; + else + { + /* Since we use the normal file functions we can also use stat() + to verify the file is there. */ + struct stat st; + size_t patlen = strlen (pattern); + size_t dirlen = strlen (directory); + char *fullname = (char *) __alloca (dirlen + 1 + patlen + 1); + +# ifdef HAVE_MEMPCPY + mempcpy (mempcpy (mempcpy (fullname, directory, dirlen), + "/", 1), + pattern, patlen + 1); +# else + memcpy (fullname, directory, dirlen); + fullname[dirlen] = '/'; + memcpy (&fullname[dirlen + 1], pattern, patlen + 1); +# endif +# ifdef KMK + if (flags & GLOB_ALTDIRFUNC ? pglob->gl_exists (fullname) : __stat (fullname, &st) == 0) +# else + if (((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_stat) (fullname, &st) + : __stat (fullname, &st)) == 0) +# endif + /* We found this file to be existing. Now tell the rest + of the function to copy this name into the result. */ + flags |= GLOB_NOCHECK; + } + + nfound = 0; + } + else + { + if (pattern[0] == '\0') + { + /* This is a special case for matching directories like in + "*a/". */ + names = (struct globlink *) __alloca (sizeof (struct globlink)); + names->name = (char *) malloc (1); + if (names->name == NULL) + goto memory_error; + names->name[0] = '\0'; + names->next = NULL; + nfound = 1; + meta = 0; + } + else + { + stream = ((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_opendir) (directory) + : (__ptr_t) opendir (directory)); + if (stream == NULL) + { + if (errno != ENOTDIR + && ((errfunc != NULL && (*errfunc) (directory, errno)) + || (flags & GLOB_ERR))) + return GLOB_ABORTED; + nfound = 0; + meta = 0; + } + else + { + int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) + | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) +#if defined HAVE_CASE_INSENSITIVE_FS + | FNM_CASEFOLD +#endif + ); + nfound = 0; + flags |= GLOB_MAGCHAR; + + while (1) + { + const char *name; + size_t len; + struct dirent *d = ((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_readdir) (stream) + : readdir ((DIR *) stream)); + if (d == NULL) + break; + if (! REAL_DIR_ENTRY (d)) + continue; + +#ifdef HAVE_D_TYPE + /* If we shall match only directories use the information + provided by the dirent call if possible. */ + if ((flags & GLOB_ONLYDIR) + && d->d_type != DT_UNKNOWN && d->d_type != DT_DIR) + continue; +#endif + + name = d->d_name; + + if (fnmatch (pattern, name, fnm_flags) == 0) + { + struct globlink *new = (struct globlink *) + __alloca (sizeof (struct globlink)); + len = NAMLEN (d); + new->name = (char *) malloc (len + 1); + if (new->name == NULL) + goto memory_error; +#ifdef HAVE_MEMPCPY + *((char *) mempcpy ((__ptr_t) new->name, name, len)) + = '\0'; +#else + memcpy ((__ptr_t) new->name, name, len); + new->name[len] = '\0'; +#endif + new->next = names; + names = new; + ++nfound; + } + } + } + } + } + + if (nfound == 0 && (flags & GLOB_NOCHECK)) + { + size_t len = strlen (pattern); + nfound = 1; + names = (struct globlink *) __alloca (sizeof (struct globlink)); + names->next = NULL; + names->name = (char *) malloc (len + 1); + if (names->name == NULL) + goto memory_error; +#ifdef HAVE_MEMPCPY + *((char *) mempcpy (names->name, pattern, len)) = '\0'; +#else + memcpy (names->name, pattern, len); + names->name[len] = '\0'; +#endif + } + + if (nfound != 0) + { + pglob->gl_pathv + = (char **) realloc (pglob->gl_pathv, + (pglob->gl_pathc + + ((flags & GLOB_DOOFFS) ? pglob->gl_offs : 0) + + nfound + 1) * + sizeof (char *)); + if (pglob->gl_pathv == NULL) + goto memory_error; + + if (flags & GLOB_DOOFFS) + while (pglob->gl_pathc < pglob->gl_offs) + pglob->gl_pathv[pglob->gl_pathc++] = NULL; + + for (; names != NULL; names = names->next) + pglob->gl_pathv[pglob->gl_pathc++] = names->name; + pglob->gl_pathv[pglob->gl_pathc] = NULL; + + pglob->gl_flags = flags; + } + + save = errno; + if (stream != NULL) + { + if (flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir) (stream); + else + closedir ((DIR *) stream); + } + __set_errno (save); + + return nfound == 0 ? GLOB_NOMATCH : 0; + + memory_error: + { + /*int*/ save = errno; + if (flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir) (stream); + else + closedir ((DIR *) stream); + __set_errno (save); + } + while (names != NULL) + { + if (names->name != NULL) + free ((__ptr_t) names->name); + names = names->next; + } + return GLOB_NOSPACE; +} + +#endif /* Not ELIDE_CODE. */ diff --git a/src/kmk/glob/glob.h b/src/kmk/glob/glob.h new file mode 100644 index 0000000..5b82140 --- /dev/null +++ b/src/kmk/glob/glob.h @@ -0,0 +1,215 @@ +/* Copyright (C) 1991, 1992, 1995, 1996, 1997, 1998 Free Software Foundation, +Inc. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this library; see the file COPYING.LIB. If not, write to the Free +Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA. */ + +#ifndef _GLOB_H +#define _GLOB_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#undef __ptr_t +#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32 +# if !defined __GLIBC__ +# undef __P +# undef __PMT +# define __P(protos) protos +# define __PMT(protos) protos +# if !defined __GNUC__ || __GNUC__ < 2 +# undef __const +# define __const const +# endif +# endif +# define __ptr_t void * +#else /* Not C++ or ANSI C. */ +# undef __P +# undef __PMT +# define __P(protos) () +# define __PMT(protos) () +# undef __const +# define __const +# define __ptr_t char * +#endif /* C++ or ANSI C. */ + +/* We need `size_t' for the following definitions. */ +#ifndef __size_t +# if defined __FreeBSD__ +# define __size_t size_t +# else +# if defined __GNUC__ && __GNUC__ >= 2 +typedef __SIZE_TYPE__ __size_t; +# else +/* This is a guess. */ +/*hb + * Conflicts with DECCs already defined type __size_t. + * Defining an own type with a name beginning with '__' is no good. + * Anyway if DECC is used and __SIZE_T is defined then __size_t is + * already defined (and I hope it's exactly the one we need here). + */ +# if !(defined __DECC && defined __SIZE_T) +typedef unsigned long int __size_t; +# endif +# endif +# endif +#else +/* The GNU CC stddef.h version defines __size_t as empty. We need a real + definition. */ +# undef __size_t +# define __size_t size_t +#endif + +/* Bits set in the FLAGS argument to `glob'. */ +#define GLOB_ERR (1 << 0)/* Return on read errors. */ +#define GLOB_MARK (1 << 1)/* Append a slash to each name. */ +#define GLOB_NOSORT (1 << 2)/* Don't sort the names. */ +#define GLOB_DOOFFS (1 << 3)/* Insert PGLOB->gl_offs NULLs. */ +#define GLOB_NOCHECK (1 << 4)/* If nothing matches, return the pattern. */ +#define GLOB_APPEND (1 << 5)/* Append to results of a previous call. */ +#define GLOB_NOESCAPE (1 << 6)/* Backslashes don't quote metacharacters. */ +#define GLOB_PERIOD (1 << 7)/* Leading `.' can be matched by metachars. */ + +#if (!defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _BSD_SOURCE \ + || defined _GNU_SOURCE) +# define GLOB_MAGCHAR (1 << 8)/* Set in gl_flags if any metachars seen. */ +# define GLOB_ALTDIRFUNC (1 << 9)/* Use gl_opendir et al functions. */ +# define GLOB_BRACE (1 << 10)/* Expand "{a,b}" to "a" "b". */ +# define GLOB_NOMAGIC (1 << 11)/* If no magic chars, return the pattern. */ +# define GLOB_TILDE (1 << 12)/* Expand ~user and ~ to home directories. */ +# define GLOB_ONLYDIR (1 << 13)/* Match only directories. */ +# define GLOB_TILDE_CHECK (1 << 14)/* Like GLOB_TILDE but return an error + if the user name is not available. */ +# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \ + GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \ + GLOB_PERIOD|GLOB_ALTDIRFUNC|GLOB_BRACE| \ + GLOB_NOMAGIC|GLOB_TILDE|GLOB_ONLYDIR|GLOB_TILDE_CHECK) +#else +# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \ + GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \ + GLOB_PERIOD) +#endif + +/* Error returns from `glob'. */ +#define GLOB_NOSPACE 1 /* Ran out of memory. */ +#define GLOB_ABORTED 2 /* Read error. */ +#define GLOB_NOMATCH 3 /* No matches found. */ +#define GLOB_NOSYS 4 /* Not implemented. */ +#ifdef _GNU_SOURCE +/* Previous versions of this file defined GLOB_ABEND instead of + GLOB_ABORTED. Provide a compatibility definition here. */ +# define GLOB_ABEND GLOB_ABORTED +#endif + +/* Structure describing a globbing run. */ +#if !defined _AMIGA && !defined VMS /* Buggy compiler. */ +struct stat; +#endif +typedef struct + { + __size_t gl_pathc; /* Count of paths matched by the pattern. */ + char **gl_pathv; /* List of matched pathnames. */ + __size_t gl_offs; /* Slots to reserve in `gl_pathv'. */ + int gl_flags; /* Set to FLAGS, maybe | GLOB_MAGCHAR. */ + + /* If the GLOB_ALTDIRFUNC flag is set, the following functions + are used instead of the normal file access functions. */ + void (*gl_closedir) __PMT ((void *)); + struct dirent *(*gl_readdir) __PMT ((void *)); + __ptr_t (*gl_opendir) __PMT ((__const char *)); + int (*gl_lstat) __PMT ((__const char *, struct stat *)); +#if defined(VMS) && defined(__DECC) && !defined(_POSIX_C_SOURCE) + int (*gl_stat) __PMT ((__const char *, struct stat *, ...)); +#else + int (*gl_stat) __PMT ((__const char *, struct stat *)); +#endif +#ifdef KMK +# define GLOB_WITH_EXTENDED_KMK_MEMBERS + int (*gl_exists) __PMT ((__const char *)); + int (*gl_isdir) __PMT ((__const char *)); +#endif + } glob_t; + +#ifdef _LARGEFILE64_SOURCE +struct stat64; +typedef struct + { + __size_t gl_pathc; + char **gl_pathv; + __size_t gl_offs; + int gl_flags; + + /* If the GLOB_ALTDIRFUNC flag is set, the following functions + are used instead of the normal file access functions. */ + void (*gl_closedir) __PMT ((void *)); + struct dirent64 *(*gl_readdir) __PMT ((void *)); + __ptr_t (*gl_opendir) __PMT ((__const char *)); + int (*gl_lstat) __PMT ((__const char *, struct stat64 *)); + int (*gl_stat) __PMT ((__const char *, struct stat64 *)); + } glob64_t; +#endif + +#if _FILE_OFFSET_BITS == 64 && __GNUC__ < 2 +# define glob glob64 +# define globfree globfree64 +#else +# ifdef _LARGEFILE64_SOURCE +extern int glob64 __P ((__const char *__pattern, int __flags, + int (*__errfunc) (__const char *, int), + glob64_t *__pglob)); + +extern void globfree64 __P ((glob64_t *__pglob)); +# endif +#endif + +/* Do glob searching for PATTERN, placing results in PGLOB. + The bits defined above may be set in FLAGS. + If a directory cannot be opened or read and ERRFUNC is not nil, + it is called with the pathname that caused the error, and the + `errno' value from the failing call; if it returns non-zero + `glob' returns GLOB_ABEND; if it returns zero, the error is ignored. + If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned. + Otherwise, `glob' returns zero. */ +#if _FILE_OFFSET_BITS != 64 || __GNUC__ < 2 +extern int glob __P ((__const char *__pattern, int __flags, + int (*__errfunc) (__const char *, int), + glob_t *__pglob)); + +/* Free storage allocated in PGLOB by a previous `glob' call. */ +extern void globfree __P ((glob_t *__pglob)); +#else +extern int glob __P ((__const char *__pattern, int __flags, + int (*__errfunc) (__const char *, int), + glob_t *__pglob)) __asm__ ("glob64"); + +extern void globfree __P ((glob_t *__pglob)) __asm__ ("globfree64"); +#endif + + +#ifdef _GNU_SOURCE +/* Return nonzero if PATTERN contains any metacharacters. + Metacharacters can be quoted with backslashes if QUOTE is nonzero. + + This function is not part of the interface specified by POSIX.2 + but several programs want to use it. */ +extern int glob_pattern_p __P ((__const char *__pattern, int __quote)); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* glob.h */ diff --git a/src/kmk/gmk-default.scm b/src/kmk/gmk-default.scm new file mode 100644 index 0000000..e7353f9 --- /dev/null +++ b/src/kmk/gmk-default.scm @@ -0,0 +1,53 @@ +;; Contents of the (gnu make) Guile module +;; Copyright (C) 2011-2016 Free Software Foundation, Inc. +;; This file is part of GNU Make. +;; +;; GNU Make is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 3 of the License, or (at your option) +;; any later version. +;; +;; GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +;; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +;; details. +;; +;; You should have received a copy of the GNU General Public License along +;; with this program. If not, see . + +(define (to-string-maybe x) + (cond + ;; In GNU make, "false" is the empty string + ((or (not x) + (unspecified? x) + (variable? x) + (null? x) + (and (string? x) (string-null? x))) + #f) + ;; We want something not false... not sure about this + ((eq? x #t) "#t") + ;; Basics + ((or (symbol? x) (number? x)) + (object->string x)) + ((char? x) + (string x)) + ;; Printable string (no special characters) + ((and (string? x) (string-every char-set:printing x)) + x) + ;; No idea: fail + (else (error "Unknown object:" x)))) + +(define (obj-to-str x) + (let ((acc '())) + (define (walk x) + (cond ((pair? x) (walk (car x)) (walk (cdr x))) + ((to-string-maybe x) => (lambda (s) (set! acc (cons s acc)))))) + (walk x) + (string-join (reverse! acc)))) + +;; Return the value of the GNU make variable V +(define (gmk-var v) + (gmk-expand (format #f "$(~a)" (obj-to-str v)))) + +;; Export the public interfaces +(export gmk-expand gmk-eval gmk-var) diff --git a/src/kmk/gnumake.h b/src/kmk/gnumake.h new file mode 100644 index 0000000..b508562 --- /dev/null +++ b/src/kmk/gnumake.h @@ -0,0 +1,79 @@ +/* External interfaces usable by dynamic objects loaded into GNU Make. + --THIS API IS A "TECHNOLOGY PREVIEW" ONLY. IT IS NOT A STABLE INTERFACE-- + +Copyright (C) 2013-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#ifndef _GNUMAKE_H_ +#define _GNUMAKE_H_ + +/* Specify the location of elements read from makefiles. */ +typedef struct + { + const char *filenm; + unsigned long lineno; + } gmk_floc; + +typedef char *(*gmk_func_ptr)(const char *nm, unsigned int argc, char **argv); + +#ifdef _WIN32 +# ifdef GMK_BUILDING_MAKE +# define GMK_EXPORT __declspec(dllexport) +# else +# define GMK_EXPORT __declspec(dllimport) +# endif +#else +# define GMK_EXPORT +#endif + +/* Free memory returned by the gmk_expand() function. */ +GMK_EXPORT void gmk_free (char *str); + +/* Allocate memory in GNU make's context. */ +GMK_EXPORT char *gmk_alloc (unsigned int len); + +/* Run $(eval ...) on the provided string BUFFER. */ +GMK_EXPORT void gmk_eval (const char *buffer, const gmk_floc *floc); + +/* Run GNU make expansion on the provided string STR. + Returns an allocated buffer that the caller must free with gmk_free(). */ +GMK_EXPORT char *gmk_expand (const char *str); + +/* Register a new GNU make function NAME (maximum of 255 chars long). + When the function is expanded in the makefile, FUNC will be invoked with + the appropriate arguments. + + The return value of FUNC must be either NULL, in which case it expands to + the empty string, or a pointer to the result of the expansion in a string + created by gmk_alloc(). GNU make will free the memory when it's done. + + MIN_ARGS is the minimum number of arguments the function requires. + MAX_ARGS is the maximum number of arguments (or 0 if there's no maximum). + MIN_ARGS and MAX_ARGS may not exceed 255. + + The FLAGS value may be GMK_FUNC_DEFAULT, or one or more of the following + flags OR'd together: + + GMK_FUNC_NOEXPAND: the arguments to the function will be not be expanded + before FUNC is called. +*/ +GMK_EXPORT void gmk_add_function (const char *name, gmk_func_ptr func, + unsigned int min_args, unsigned int max_args, + unsigned int flags); + +#define GMK_FUNC_DEFAULT 0x00 +#define GMK_FUNC_NOEXPAND 0x01 + +#endif /* _GNUMAKE_H_ */ diff --git a/src/kmk/guile.c b/src/kmk/guile.c new file mode 100644 index 0000000..1b055c3 --- /dev/null +++ b/src/kmk/guile.c @@ -0,0 +1,159 @@ +/* GNU Guile interface for GNU Make. +Copyright (C) 2011-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#include "makeint.h" + +#ifdef HAVE_GUILE + +#include "gnumake.h" + +#include "debug.h" +#include "filedef.h" +#include "dep.h" +#include "variable.h" + +#include + +/* Pre-2.0 versions of Guile don't have a typedef for gsubr function types. */ +#if SCM_MAJOR_VERSION < 2 +# define GSUBR_TYPE SCM (*) () +/* Guile 1.x doesn't really support i18n. */ +# define EVAL_STRING(_s) scm_c_eval_string (_s) +#else +# define GSUBR_TYPE scm_t_subr +# define EVAL_STRING(_s) scm_eval_string (scm_from_utf8_string (_s)) +#endif + +static SCM make_mod = SCM_EOL; +static SCM obj_to_str = SCM_EOL; + +/* Convert an SCM object into a string. */ +static char * +cvt_scm_to_str (SCM obj) +{ + return scm_to_locale_string (scm_call_1 (obj_to_str, obj)); +} + +/* Perform the GNU make expansion function. */ +static SCM +guile_expand_wrapper (SCM obj) +{ + char *str = cvt_scm_to_str (obj); + SCM ret; + char *res; + + DB (DB_BASIC, (_("guile: Expanding '%s'\n"), str)); + res = gmk_expand (str); + ret = scm_from_locale_string (res); + + free (str); + free (res); + + return ret; +} + +/* Perform the GNU make eval function. */ +static SCM +guile_eval_wrapper (SCM obj) +{ + char *str = cvt_scm_to_str (obj); + + DB (DB_BASIC, (_("guile: Evaluating '%s'\n"), str)); + gmk_eval (str, 0); + + return SCM_BOOL_F; +} + +/* Invoked by scm_c_define_module(), in the context of the GNU make module. */ +static void +guile_define_module (void *data UNUSED) +{ +/* Ingest the predefined Guile module for GNU make. */ +#include "gmk-default.h" + + /* Register a subr for GNU make's eval capability. */ + scm_c_define_gsubr ("gmk-expand", 1, 0, 0, (GSUBR_TYPE) guile_expand_wrapper); + + /* Register a subr for GNU make's eval capability. */ + scm_c_define_gsubr ("gmk-eval", 1, 0, 0, (GSUBR_TYPE) guile_eval_wrapper); + + /* Define the rest of the module. */ + scm_c_eval_string (GUILE_module_defn); +} + +/* Initialize the GNU make Guile module. */ +static void * +guile_init (void *arg UNUSED) +{ + /* Define the module. */ + make_mod = scm_c_define_module ("gnu make", guile_define_module, NULL); + + /* Get a reference to the object-to-string translator, for later. */ + obj_to_str = scm_variable_ref (scm_c_module_lookup (make_mod, "obj-to-str")); + + /* Import the GNU make module exports into the generic space. */ + scm_c_eval_string ("(use-modules (gnu make))"); + + return NULL; +} + +static void * +internal_guile_eval (void *arg) +{ + return cvt_scm_to_str (EVAL_STRING (arg)); +} + +/* This is the function registered with make */ +static char * +func_guile (const char *funcname UNUSED, unsigned int argc UNUSED, char **argv) +{ + static int init = 0; + + if (! init) + { + /* Initialize the Guile interpreter. */ + scm_with_guile (guile_init, NULL); + init = 1; + } + + if (argv[0] && argv[0][0] != '\0') + return scm_with_guile (internal_guile_eval, argv[0]); + + return NULL; +} + +/* ----- Public interface ----- */ + +/* We could send the flocp to define_new_function(), but since guile is + "kind of" built-in, that didn't seem so useful. */ +int +guile_gmake_setup (const floc *flocp UNUSED) +{ + /* Create a make function "guile". */ + gmk_add_function ("guile", func_guile, 0, 1, GMK_FUNC_DEFAULT); + + return 1; +} + +#else + +int +guile_gmake_setup (const floc *flocp UNUSED) +{ + return 1; +} + +#endif diff --git a/src/kmk/hash.c b/src/kmk/hash.c new file mode 100644 index 0000000..070d2e4 --- /dev/null +++ b/src/kmk/hash.c @@ -0,0 +1,536 @@ +/* hash.c -- hash table maintenance +Copyright (C) 1995, 1999, 2002, 2010 Free Software Foundation, Inc. +Written by Greg McGary + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#include "makeint.h" +#include "hash.h" +#ifdef CONFIG_WITH_STRCACHE2 +# include +#endif + +#define CALLOC(t, n) ((t *) xcalloc (sizeof (t) * (n))) +#define MALLOC(t, n) ((t *) xmalloc (sizeof (t) * (n))) +#define REALLOC(o, t, n) ((t *) xrealloc ((o), sizeof (t) * (n))) +#define CLONE(o, t, n) ((t *) memcpy (MALLOC (t, (n)), (o), sizeof (t) * (n))) + +static void hash_rehash __P((struct hash_table* ht)); +static unsigned long round_up_2 __P((unsigned long rough)); + +/* Implement double hashing with open addressing. The table size is + always a power of two. The secondary ('increment') hash function + is forced to return an odd-value, in order to be relatively prime + to the table size. This guarantees that the increment can + potentially hit every slot in the table during collision + resolution. */ + +void *hash_deleted_item = &hash_deleted_item; + +/* Force the table size to be a power of two, possibly rounding up the + given size. */ + +void +hash_init (struct hash_table *ht, unsigned long size, + hash_func_t hash_1, hash_func_t hash_2, hash_cmp_func_t hash_cmp) +{ + ht->ht_size = round_up_2 (size); + ht->ht_empty_slots = ht->ht_size; + ht->ht_vec = (void**) CALLOC (struct token *, ht->ht_size); + if (ht->ht_vec == 0) + { + fprintf (stderr, _("can't allocate %lu bytes for hash table: memory exhausted"), + ht->ht_size * (unsigned long) sizeof (struct token *)); + exit (MAKE_TROUBLE); + } + + ht->ht_capacity = ht->ht_size - (ht->ht_size / 16); /* 93.75% loading factor */ + ht->ht_fill = 0; + ht->ht_collisions = 0; + ht->ht_lookups = 0; + ht->ht_rehashes = 0; + ht->ht_hash_1 = hash_1; + ht->ht_hash_2 = hash_2; + ht->ht_compare = hash_cmp; +#ifdef CONFIG_WITH_STRCACHE2 + ht->ht_strcache = 0; + ht->ht_off_string = 0; +#endif +} + +#ifdef CONFIG_WITH_STRCACHE2 +/* Same as hash_init, except that no callbacks are needed since all + keys - including the ones being searched for - are from a string + cache. This means that any give string will only have one pointer + value and that the hash and length can be retrived very cheaply, + thus permitting some nice optimizations. + + STRCACHE points to the string cache, while OFF_STRING gives the + offset of the string pointer in the item structures the hash table + entries points to. */ +void hash_init_strcached (struct hash_table *ht, unsigned long size, + struct strcache2 *strcache, unsigned int off_string) +{ + hash_init (ht, size, 0, 0, 0); + ht->ht_strcache = strcache; + ht->ht_off_string = off_string; +} +#endif /* CONFIG_WITH_STRCACHE2 */ + +/* Load an array of items into 'ht'. */ + +void +hash_load (struct hash_table *ht, void *item_table, + unsigned long cardinality, unsigned long size) +{ + char *items = (char *) item_table; +#ifndef CONFIG_WITH_STRCACHE2 + while (cardinality--) + { + hash_insert (ht, items); + items += size; + } +#else /* CONFIG_WITH_STRCACHE2 */ + if (ht->ht_strcache) + while (cardinality--) + { + hash_insert_strcached (ht, items); + items += size; + } + else + while (cardinality--) + { + hash_insert (ht, items); + items += size; + } +#endif /* CONFIG_WITH_STRCACHE2 */ +} + +/* Returns the address of the table slot matching 'key'. If 'key' is + not found, return the address of an empty slot suitable for + inserting 'key'. The caller is responsible for incrementing + ht_fill on insertion. */ + +void ** +hash_find_slot (struct hash_table *ht, const void *key) +{ + void **slot; + void **deleted_slot = 0; + unsigned int hash_2 = 0; + unsigned int hash_1 = (*ht->ht_hash_1) (key); + +#ifdef CONFIG_WITH_STRCACHE2 + assert (ht->ht_strcache == 0); +#endif + + MAKE_STATS (ht->ht_lookups++); + MAKE_STATS_3 (make_stats_ht_lookups++); + for (;;) + { + hash_1 &= (ht->ht_size - 1); + slot = &ht->ht_vec[hash_1]; + + if (*slot == 0) + return (deleted_slot ? deleted_slot : slot); + if (*slot == hash_deleted_item) + { + if (deleted_slot == 0) + deleted_slot = slot; + } + else + { + if (key == *slot) + return slot; + if ((*ht->ht_compare) (key, *slot) == 0) + return slot; + MAKE_STATS (ht->ht_collisions++); + MAKE_STATS_3 (make_stats_ht_collisions++); + } + if (!hash_2) + hash_2 = (*ht->ht_hash_2) (key) | 1; + hash_1 += hash_2; + } +} + +#ifdef CONFIG_WITH_STRCACHE2 +/* hash_find_slot version for tables created with hash_init_strcached. */ +void ** +hash_find_slot_strcached (struct hash_table *ht, const void *key) +{ + void **slot; + void **deleted_slot = 0; + const char *str1 = *(const char **)((const char *)key + ht->ht_off_string); + const char *str2; + unsigned int hash_1 = strcache2_calc_ptr_hash (ht->ht_strcache, str1); + unsigned int hash_2; + +#ifdef CONFIG_WITH_STRCACHE2 + assert (ht->ht_strcache != 0); +#endif + + MAKE_STATS (ht->ht_lookups++); + MAKE_STATS_3 (make_stats_ht_lookups++); + + /* first iteration unrolled. */ + + hash_1 &= (ht->ht_size - 1); + slot = &ht->ht_vec[hash_1]; + if (*slot == 0) + return slot; + if (*slot != hash_deleted_item) + { + str2 = *(const char **)((const char *)(*slot) + ht->ht_off_string); + if (str1 == str2) + return slot; + + MAKE_STATS (ht->ht_collisions++); + MAKE_STATS_3 (make_stats_ht_collisions++); + } + else + deleted_slot = slot; + + /* the rest of the loop. */ + + hash_2 = strcache2_get_hash (ht->ht_strcache, str1) | 1; + hash_1 += hash_2; + for (;;) + { + hash_1 &= (ht->ht_size - 1); + slot = &ht->ht_vec[hash_1]; + + if (*slot == 0) + return (deleted_slot ? deleted_slot : slot); + if (*slot == hash_deleted_item) + { + if (deleted_slot == 0) + deleted_slot = slot; + } + else + { + str2 = *(const char **)((const char *)(*slot) + ht->ht_off_string); + if (str1 == str2) + return slot; + + MAKE_STATS (ht->ht_collisions++); + MAKE_STATS_3 (make_stats_ht_collisions++); + } + + hash_1 += hash_2; + } +} +#endif /* CONFIG_WITH_STRCACHE2 */ + +void * +hash_find_item (struct hash_table *ht, const void *key) +{ + void **slot = hash_find_slot (ht, key); + return ((HASH_VACANT (*slot)) ? 0 : *slot); +} + +#ifdef CONFIG_WITH_STRCACHE2 +void * +hash_find_item_strcached (struct hash_table *ht, const void *key) +{ + void **slot = hash_find_slot_strcached (ht, key); + return ((HASH_VACANT (*slot)) ? 0 : *slot); +} +#endif /* CONFIG_WITH_STRCACHE2 */ + +void * +hash_insert (struct hash_table *ht, const void *item) +{ + void **slot = hash_find_slot (ht, item); + const void *old_item = *slot; + hash_insert_at (ht, item, slot); + return (void *)((HASH_VACANT (old_item)) ? 0 : old_item); +} + +#ifdef CONFIG_WITH_STRCACHE2 +void * +hash_insert_strcached (struct hash_table *ht, const void *item) +{ + void **slot = hash_find_slot_strcached (ht, item); + const void *old_item = slot ? *slot : 0; + hash_insert_at (ht, item, slot); + return (void *)((HASH_VACANT (old_item)) ? 0 : old_item); +} +#endif /* CONFIG_WITH_STRCACHE2 */ + +void * +hash_insert_at (struct hash_table *ht, const void *item, const void *slot) +{ + const void *old_item = *(void **) slot; + if (HASH_VACANT (old_item)) + { + ht->ht_fill++; + if (old_item == 0) + ht->ht_empty_slots--; + old_item = item; + } + *(void const **) slot = item; + if (ht->ht_empty_slots < ht->ht_size - ht->ht_capacity) + { + hash_rehash (ht); +#ifdef CONFIG_WITH_STRCACHE2 + if (ht->ht_strcache) + return (void *)hash_find_slot_strcached (ht, item); +#endif /* CONFIG_WITH_STRCACHE2 */ + return (void *) hash_find_slot (ht, item); + } + else + return (void *) slot; +} + +void * +hash_delete (struct hash_table *ht, const void *item) +{ + void **slot = hash_find_slot (ht, item); + return hash_delete_at (ht, slot); +} + +#ifdef CONFIG_WITH_STRCACHE2 +void * +hash_delete_strcached (struct hash_table *ht, const void *item) +{ + void **slot = hash_find_slot_strcached (ht, item); + return hash_delete_at (ht, slot); +} +#endif /* CONFIG_WITH_STRCACHE2 */ + +void * +hash_delete_at (struct hash_table *ht, const void *slot) +{ + void *item = *(void **) slot; + if (!HASH_VACANT (item)) + { + *(void const **) slot = hash_deleted_item; + ht->ht_fill--; + return item; + } + else + return 0; +} + +void +hash_free_items (struct hash_table *ht) +{ + void **vec = ht->ht_vec; + void **end = &vec[ht->ht_size]; + for (; vec < end; vec++) + { + void *item = *vec; + if (!HASH_VACANT (item)) + free (item); + *vec = 0; + } + ht->ht_fill = 0; + ht->ht_empty_slots = ht->ht_size; +} + +#ifdef CONFIG_WITH_ALLOC_CACHES +void +hash_free_items_cached (struct hash_table *ht, struct alloccache *cache) +{ + void **vec = ht->ht_vec; + void **end = &vec[ht->ht_size]; + for (; vec < end; vec++) + { + void *item = *vec; + if (!HASH_VACANT (item)) + alloccache_free (cache, item); + *vec = 0; + } + ht->ht_fill = 0; + ht->ht_empty_slots = ht->ht_size; +} +#endif /* CONFIG_WITH_ALLOC_CACHES */ + +void +hash_delete_items (struct hash_table *ht) +{ + void **vec = ht->ht_vec; + void **end = &vec[ht->ht_size]; + for (; vec < end; vec++) + *vec = 0; + ht->ht_fill = 0; + ht->ht_collisions = 0; + ht->ht_lookups = 0; + ht->ht_rehashes = 0; + ht->ht_empty_slots = ht->ht_size; +} + +void +hash_free (struct hash_table *ht, int free_items) +{ + if (free_items) + hash_free_items (ht); + else + { + ht->ht_fill = 0; + ht->ht_empty_slots = ht->ht_size; + } + free (ht->ht_vec); + ht->ht_vec = 0; + ht->ht_capacity = 0; +} + +#ifdef CONFIG_WITH_ALLOC_CACHES +void +hash_free_cached (struct hash_table *ht, int free_items, struct alloccache *cache) +{ + if (free_items) + hash_free_items_cached (ht, cache); + else + { + ht->ht_fill = 0; + ht->ht_empty_slots = ht->ht_size; + } + free (ht->ht_vec); + ht->ht_vec = 0; + ht->ht_capacity = 0; +} +#endif /* CONFIG_WITH_ALLOC_CACHES */ + +void +hash_map (struct hash_table *ht, hash_map_func_t map) +{ + void **slot; + void **end = &ht->ht_vec[ht->ht_size]; + + for (slot = ht->ht_vec; slot < end; slot++) + { + if (!HASH_VACANT (*slot)) + (*map) (*slot); + } +} + +void +hash_map_arg (struct hash_table *ht, hash_map_arg_func_t map, void *arg) +{ + void **slot; + void **end = &ht->ht_vec[ht->ht_size]; + + for (slot = ht->ht_vec; slot < end; slot++) + { + if (!HASH_VACANT (*slot)) + (*map) (*slot, arg); + } +} + +/* Double the size of the hash table in the event of overflow... */ + +static void +hash_rehash (struct hash_table *ht) +{ + unsigned long old_ht_size = ht->ht_size; + void **old_vec = ht->ht_vec; + void **ovp; + + if (ht->ht_fill >= ht->ht_capacity) + { + ht->ht_size *= 2; + ht->ht_capacity = ht->ht_size - (ht->ht_size >> 4); + } + ht->ht_rehashes++; + ht->ht_vec = (void **) CALLOC (struct token *, ht->ht_size); + +#ifndef CONFIG_WITH_STRCACHE2 + for (ovp = old_vec; ovp < &old_vec[old_ht_size]; ovp++) + { + if (! HASH_VACANT (*ovp)) + { + void **slot = hash_find_slot (ht, *ovp); + *slot = *ovp; + } + } +#else /* CONFIG_WITH_STRCACHE2 */ + if (ht->ht_strcache) + for (ovp = old_vec; ovp < &old_vec[old_ht_size]; ovp++) + { + if (! HASH_VACANT (*ovp)) + { + void **slot = hash_find_slot_strcached (ht, *ovp); + *slot = *ovp; + } + } + else + for (ovp = old_vec; ovp < &old_vec[old_ht_size]; ovp++) + { + if (! HASH_VACANT (*ovp)) + { + void **slot = hash_find_slot (ht, *ovp); + *slot = *ovp; + } + } +#endif /* CONFIG_WITH_STRCACHE2 */ + ht->ht_empty_slots = ht->ht_size - ht->ht_fill; + free (old_vec); +} + +void +hash_print_stats (struct hash_table *ht, FILE *out_FILE) +{ + /* GKM FIXME: honor NO_FLOAT */ + fprintf (out_FILE, _("Load=%ld/%ld=%.0f%%, "), ht->ht_fill, ht->ht_size, + 100.0 * (double) ht->ht_fill / (double) ht->ht_size); + fprintf (out_FILE, _("Rehash=%d, "), ht->ht_rehashes); + MAKE_STATS( + fprintf (out_FILE, _("Collisions=%ld/%ld=%.0f%%"), ht->ht_collisions, ht->ht_lookups, + (ht->ht_lookups + ? (100.0 * (double) ht->ht_collisions / (double) ht->ht_lookups) + : 0)); + ); +} + +/* Dump all items into a NULL-terminated vector. Use the + user-supplied vector, or malloc one. */ + +void ** +hash_dump (struct hash_table *ht, void **vector_0, qsort_cmp_t compare) +{ + void **vector; + void **slot; + void **end = &ht->ht_vec[ht->ht_size]; + + if (vector_0 == 0) + vector_0 = MALLOC (void *, ht->ht_fill + 1); + vector = vector_0; + + for (slot = ht->ht_vec; slot < end; slot++) + if (!HASH_VACANT (*slot)) + *vector++ = *slot; + *vector = 0; + + if (compare) + qsort (vector_0, ht->ht_fill, sizeof (void *), compare); + return vector_0; +} + +/* Round a given number up to the nearest power of 2. */ + +static unsigned long +round_up_2 (unsigned long n) +{ + n |= (n >> 1); + n |= (n >> 2); + n |= (n >> 4); + n |= (n >> 8); + n |= (n >> 16); + +#if !defined(HAVE_LIMITS_H) || ULONG_MAX > 4294967295 + /* We only need this on systems where unsigned long is >32 bits. */ + n |= (n >> 32); +#endif + + return n + 1; +} diff --git a/src/kmk/hash.h b/src/kmk/hash.h new file mode 100644 index 0000000..0a43369 --- /dev/null +++ b/src/kmk/hash.h @@ -0,0 +1,251 @@ +/* hash.h -- decls for hash table +Copyright (C) 1995, 1999, 2002, 2010 Free Software Foundation, Inc. +Written by Greg McGary + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#ifndef _hash_h_ +#define _hash_h_ + +#include +#include + +#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32 +# if !defined __GLIBC__ || !defined __P +# undef __P +# define __P(protos) protos +# endif +#else /* Not C++ or ANSI C. */ +# undef __P +# define __P(protos) () +/* We can get away without defining 'const' here only because in this file + it is used only inside the prototype for 'fnmatch', which is elided in + non-ANSI C where 'const' is problematical. */ +#endif /* C++ or ANSI C. */ + +typedef unsigned long (*hash_func_t) __P((void const *key)); +typedef int (*hash_cmp_func_t) __P((void const *x, void const *y)); +typedef void (*hash_map_func_t) __P((void const *item)); +typedef void (*hash_map_arg_func_t) __P((void const *item, void *arg)); + +struct hash_table +{ + void **ht_vec; + hash_func_t ht_hash_1; /* primary hash function */ + hash_func_t ht_hash_2; /* secondary hash function */ + hash_cmp_func_t ht_compare; /* comparison function */ + unsigned long ht_size; /* total number of slots (power of 2) */ + unsigned long ht_capacity; /* usable slots, limited by loading-factor */ + unsigned long ht_fill; /* items in table */ + unsigned long ht_empty_slots; /* empty slots not including deleted slots */ + unsigned long ht_collisions; /* # of failed calls to comparison function */ + unsigned long ht_lookups; /* # of queries */ + unsigned int ht_rehashes; /* # of times we've expanded table */ +#ifdef CONFIG_WITH_STRCACHE2 + struct strcache2 *ht_strcache; /* the string cache pointer. */ + unsigned int ht_off_string; /* offsetof (struct key, string) */ +#endif +}; + +typedef int (*qsort_cmp_t) __P((void const *, void const *)); + +void hash_init __P((struct hash_table *ht, unsigned long size, + hash_func_t hash_1, hash_func_t hash_2, hash_cmp_func_t hash_cmp)); +void hash_load __P((struct hash_table *ht, void *item_table, + unsigned long cardinality, unsigned long size)); +void **hash_find_slot __P((struct hash_table *ht, void const *key)); +void *hash_find_item __P((struct hash_table *ht, void const *key)); +void *hash_insert __P((struct hash_table *ht, const void *item)); +void *hash_insert_at __P((struct hash_table *ht, const void *item, void const *slot)); +void *hash_delete __P((struct hash_table *ht, void const *item)); +void *hash_delete_at __P((struct hash_table *ht, void const *slot)); +void hash_delete_items __P((struct hash_table *ht)); +void hash_free_items __P((struct hash_table *ht)); +void hash_free __P((struct hash_table *ht, int free_items)); +#ifdef CONFIG_WITH_ALLOC_CACHES +void hash_free_items_cached __P((struct hash_table *ht, struct alloccache *cache)); +void hash_free_cached __P((struct hash_table *ht, int free_items, struct alloccache *cache)); +#endif +void hash_map __P((struct hash_table *ht, hash_map_func_t map)); +void hash_map_arg __P((struct hash_table *ht, hash_map_arg_func_t map, void *arg)); +void hash_print_stats __P((struct hash_table *ht, FILE *out_FILE)); +void **hash_dump __P((struct hash_table *ht, void **vector_0, qsort_cmp_t compare)); + +#ifdef CONFIG_WITH_STRCACHE2 +void hash_init_strcached __P((struct hash_table *ht, unsigned long size, + struct strcache2 *strcache, unsigned int off_strptr)); +void **hash_find_slot_strcached __P((struct hash_table *ht, const void *key)); +void *hash_find_item_strcached __P((struct hash_table *ht, void const *key)); +void *hash_insert_strcached __P((struct hash_table *ht, const void *item)); +void *hash_delete_strcached __P((struct hash_table *ht, void const *item)); +#endif /* CONFIG_WITH_STRCACHE2 */ + +extern void *hash_deleted_item; +#define HASH_VACANT(item) ((item) == 0 || (void *) (item) == hash_deleted_item) + + +/* hash and comparison macros for case-sensitive string keys. */ + +/* Due to the strcache, it's not uncommon for the string pointers to + be identical. Take advantage of that to short-circuit string compares. */ + +#define STRING_HASH_1(KEY, RESULT) do { \ + unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \ + while (*++_key_) \ + (RESULT) += (*_key_ << (_key_[1] & 0xf)); \ +} while (0) +#define return_STRING_HASH_1(KEY) do { \ + unsigned long _result_ = 0; \ + STRING_HASH_1 ((KEY), _result_); \ + return _result_; \ +} while (0) + +#define STRING_HASH_2(KEY, RESULT) do { \ + unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \ + while (*++_key_) \ + (RESULT) += (*_key_ << (_key_[1] & 0x7)); \ +} while (0) +#define return_STRING_HASH_2(KEY) do { \ + unsigned long _result_ = 0; \ + STRING_HASH_2 ((KEY), _result_); \ + return _result_; \ +} while (0) + +#define STRING_COMPARE(X, Y, RESULT) do { \ + RESULT = (X) == (Y) ? 0 : strcmp ((X), (Y)); \ +} while (0) +#define return_STRING_COMPARE(X, Y) do { \ + return (X) == (Y) ? 0 : strcmp ((X), (Y)); \ +} while (0) + + +#define STRING_N_HASH_1(KEY, N, RESULT) do { \ + unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \ + int _n_ = (N); \ + if (_n_) \ + while (--_n_ && *++_key_) \ + (RESULT) += (*_key_ << (_key_[1] & 0xf)); \ + (RESULT) += *++_key_; \ +} while (0) +#define return_STRING_N_HASH_1(KEY, N) do { \ + unsigned long _result_ = 0; \ + STRING_N_HASH_1 ((KEY), (N), _result_); \ + return _result_; \ +} while (0) + +#define STRING_N_HASH_2(KEY, N, RESULT) do { \ + unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \ + int _n_ = (N); \ + if (_n_) \ + while (--_n_ && *++_key_) \ + (RESULT) += (*_key_ << (_key_[1] & 0x7)); \ + (RESULT) += *++_key_; \ +} while (0) +#define return_STRING_N_HASH_2(KEY, N) do { \ + unsigned long _result_ = 0; \ + STRING_N_HASH_2 ((KEY), (N), _result_); \ + return _result_; \ +} while (0) + +#define STRING_N_COMPARE(X, Y, N, RESULT) do { \ + RESULT = (X) == (Y) ? 0 : strncmp ((X), (Y), (N)); \ +} while (0) +#define return_STRING_N_COMPARE(X, Y, N) do { \ + return (X) == (Y) ? 0 : strncmp ((X), (Y), (N)); \ +} while (0) + +#ifdef HAVE_CASE_INSENSITIVE_FS + +/* hash and comparison macros for case-insensitive string _key_s. */ + +#define ISTRING_HASH_1(KEY, RESULT) do { \ + unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \ + while (*++_key_) \ + (RESULT) += ((isupper (*_key_) ? tolower (*_key_) : *_key_) << (_key_[1] & 0xf)); \ +} while (0) +#define return_ISTRING_HASH_1(KEY) do { \ + unsigned long _result_ = 0; \ + ISTRING_HASH_1 ((KEY), _result_); \ + return _result_; \ +} while (0) + +#define ISTRING_HASH_2(KEY, RESULT) do { \ + unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \ + while (*++_key_) \ + (RESULT) += ((isupper (*_key_) ? tolower (*_key_) : *_key_) << (_key_[1] & 0x7)); \ +} while (0) +#define return_ISTRING_HASH_2(KEY) do { \ + unsigned long _result_ = 0; \ + ISTRING_HASH_2 ((KEY), _result_); \ + return _result_; \ +} while (0) + +#define ISTRING_COMPARE(X, Y, RESULT) do { \ + RESULT = (X) == (Y) ? 0 : strcasecmp ((X), (Y)); \ +} while (0) +#define return_ISTRING_COMPARE(X, Y) do { \ + return (X) == (Y) ? 0 : strcasecmp ((X), (Y)); \ +} while (0) + +#else + +#define ISTRING_HASH_1(KEY, RESULT) STRING_HASH_1 ((KEY), (RESULT)) +#define return_ISTRING_HASH_1(KEY) return_STRING_HASH_1 (KEY) + +#define ISTRING_HASH_2(KEY, RESULT) STRING_HASH_2 ((KEY), (RESULT)) +#define return_ISTRING_HASH_2(KEY) return_STRING_HASH_2 (KEY) + +#define ISTRING_COMPARE(X, Y, RESULT) STRING_COMPARE ((X), (Y), (RESULT)) +#define return_ISTRING_COMPARE(X, Y) return_STRING_COMPARE ((X), (Y)) + +#endif + +/* hash and comparison macros for integer _key_s. */ + +#define INTEGER_HASH_1(KEY, RESULT) do { \ + (RESULT) += ((unsigned long)(KEY)); \ +} while (0) +#define return_INTEGER_HASH_1(KEY) do { \ + unsigned long _result_ = 0; \ + INTEGER_HASH_1 ((KEY), _result_); \ + return _result_; \ +} while (0) + +#define INTEGER_HASH_2(KEY, RESULT) do { \ + (RESULT) += ~((unsigned long)(KEY)); \ +} while (0) +#define return_INTEGER_HASH_2(KEY) do { \ + unsigned long _result_ = 0; \ + INTEGER_HASH_2 ((KEY), _result_); \ + return _result_; \ +} while (0) + +#define INTEGER_COMPARE(X, Y, RESULT) do { \ + (RESULT) = X - Y; \ +} while (0) +#define return_INTEGER_COMPARE(X, Y) do { \ + int _result_; \ + INTEGER_COMPARE (X, Y, _result_); \ + return _result_; \ +} while (0) + +/* hash and comparison macros for address keys. */ + +#define ADDRESS_HASH_1(KEY, RESULT) INTEGER_HASH_1 (((unsigned long)(KEY)) >> 3, (RESULT)) +#define ADDRESS_HASH_2(KEY, RESULT) INTEGER_HASH_2 (((unsigned long)(KEY)) >> 3, (RESULT)) +#define ADDRESS_COMPARE(X, Y, RESULT) INTEGER_COMPARE ((X), (Y), (RESULT)) +#define return_ADDRESS_HASH_1(KEY) return_INTEGER_HASH_1 (((unsigned long)(KEY)) >> 3) +#define return_ADDRESS_HASH_2(KEY) return_INTEGER_HASH_2 (((unsigned long)(KEY)) >> 3) +#define return_ADDRESS_COMPARE(X, Y) return_INTEGER_COMPARE ((X), (Y)) + +#endif /* not _hash_h_ */ diff --git a/src/kmk/implicit.c b/src/kmk/implicit.c new file mode 100644 index 0000000..0658470 --- /dev/null +++ b/src/kmk/implicit.c @@ -0,0 +1,1011 @@ +/* Implicit rule searching for GNU Make. +Copyright (C) 1988-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#include "makeint.h" +#include "filedef.h" +#include "rule.h" +#include "dep.h" +#include "debug.h" +#include "variable.h" +#include "job.h" /* struct child, used inside commands.h */ +#include "commands.h" /* set_file_variables */ + +static int pattern_search (struct file *file, int archive, + unsigned int depth, unsigned int recursions); + +/* For a FILE which has no commands specified, try to figure out some + from the implicit pattern rules. + Returns 1 if a suitable implicit rule was found, + after modifying FILE to contain the appropriate commands and deps, + or returns 0 if no implicit rule was found. */ + +int +try_implicit_rule (struct file *file, unsigned int depth) +{ + DBF (DB_IMPLICIT, _("Looking for an implicit rule for '%s'.\n")); + + /* The order of these searches was previously reversed. My logic now is + that since the non-archive search uses more information in the target + (the archive search omits the archive name), it is more specific and + should come first. */ + + if (pattern_search (file, 0, depth, 0)) + return 1; + +#ifndef NO_ARCHIVES + /* If this is an archive member reference, use just the + archive member name to search for implicit rules. */ + if (ar_name (file->name)) + { + DBF (DB_IMPLICIT, + _("Looking for archive-member implicit rule for '%s'.\n")); + if (pattern_search (file, 1, depth, 0)) + return 1; + } +#endif + + return 0; +} + + +/* Scans the BUFFER for the next word with whitespace as a separator. + Returns the pointer to the beginning of the word. LENGTH hold the + length of the word. */ + +static const char * +get_next_word (const char *buffer, unsigned int *length) +{ + const char *p = buffer, *beg; + char c; + + /* Skip any leading whitespace. */ + NEXT_TOKEN (p); + + beg = p; + c = *(p++); + + if (c == '\0') + { + if (length) /* bird: shut up gcc. */ + *length = 0; + return 0; + } + + + /* We already found the first value of "c", above. */ + while (1) + { + char closeparen; + int count; + + switch (c) + { + case '\0': + case ' ': + case '\t': + goto done_word; + + case '$': + c = *(p++); + if (c == '$') + break; + + /* This is a variable reference, so read it to the matching + close paren. */ + + if (c == '(') + closeparen = ')'; + else if (c == '{') + closeparen = '}'; + else + /* This is a single-letter variable reference. */ + break; + + for (count = 0; *p != '\0'; ++p) + { + if (*p == c) + ++count; + else if (*p == closeparen && --count < 0) + { + ++p; + break; + } + } + break; + + case '|': + goto done; + + default: + break; + } + + c = *(p++); + } + done_word: + --p; + + done: + if (length) + *length = p - beg; + + return beg; +} + +/* This structure stores information about the expanded prerequisites for a + pattern rule. NAME is always set to the strcache'd name of the prereq. + FILE and PATTERN will be set for intermediate files only. IGNORE_MTIME is + copied from the prerequisite we expanded. + */ +struct patdeps + { + const char *name; + const char *pattern; + struct file *file; + unsigned int ignore_mtime : 1; + }; + +/* This structure stores information about pattern rules that we need + to try. +*/ +struct tryrule + { + struct rule *rule; + + /* Index of the target in this rule that matched the file. */ + unsigned int matches; + + /* Stem length for this match. */ + unsigned int stemlen; + + /* Definition order of this rule. Used to implement stable sort.*/ + unsigned int order; + + /* Nonzero if the LASTSLASH logic was used in matching this rule. */ + char checked_lastslash; + }; + +int +stemlen_compare (const void *v1, const void *v2) +{ + const struct tryrule *r1 = v1; + const struct tryrule *r2 = v2; + int r = r1->stemlen - r2->stemlen; + return r != 0 ? r : (int)(r1->order - r2->order); +} + +/* Search the pattern rules for a rule with an existing dependency to make + FILE. If a rule is found, the appropriate commands and deps are put in FILE + and 1 is returned. If not, 0 is returned. + + If ARCHIVE is nonzero, FILE->name is of the form "LIB(MEMBER)". A rule for + "(MEMBER)" will be searched for, and "(MEMBER)" will not be chopped up into + directory and filename parts. + + If an intermediate file is found by pattern search, the intermediate file + is set up as a target by the recursive call and is also made a dependency + of FILE. + + DEPTH is used for debugging messages. */ + +static int +pattern_search (struct file *file, int archive, + unsigned int depth, unsigned int recursions) +{ + /* Filename we are searching for a rule for. */ + const char *filename = archive ? strchr (file->name, '(') : file->name; + + /* Length of FILENAME. */ + unsigned int namelen = strlen (filename); + + /* The last slash in FILENAME (or nil if there is none). */ + const char *lastslash; + + /* This is a file-object used as an argument in + recursive calls. It never contains any data + except during a recursive call. */ + struct file *int_file = 0; + + /* List of dependencies found recursively. */ + unsigned int max_deps = max_pattern_deps; + struct patdeps *deplist = xmalloc (max_deps * sizeof (struct patdeps)); + struct patdeps *pat = deplist; + + /* Names of possible dependencies are constructed in this buffer. */ + char *depname = alloca (namelen + max_pattern_dep_length); + + /* The start and length of the stem of FILENAME for the current rule. */ + const char *stem = 0; + unsigned int stemlen = 0; + unsigned int fullstemlen = 0; + + /* Buffer in which we store all the rules that are possibly applicable. */ + struct tryrule *tryrules = xmalloc (num_pattern_rules * max_pattern_targets + * sizeof (struct tryrule)); + + /* Number of valid elements in TRYRULES. */ + unsigned int nrules; + + /* The index in TRYRULES of the rule we found. */ + unsigned int foundrule; + + /* Nonzero if should consider intermediate files as dependencies. */ + int intermed_ok; + + /* Nonzero if we have initialized file variables for this target. */ + int file_vars_initialized = 0; + + /* Nonzero if we have matched a pattern-rule target + that is not just '%'. */ + int specific_rule_matched = 0; + + unsigned int ri; /* uninit checks OK */ + struct rule *rule; + + char *pathdir = NULL; + unsigned long pathlen; + + PATH_VAR (stem_str); /* @@ Need to get rid of stem, stemlen, etc. */ + +#ifndef NO_ARCHIVES + if (archive || ar_name (filename)) + lastslash = 0; + else +#endif + { + /* Set LASTSLASH to point at the last slash in FILENAME + but not counting any slash at the end. (foo/bar/ counts as + bar/ in directory foo/, not empty in directory foo/bar/.) */ + lastslash = strrchr (filename, '/'); +#ifdef VMS + if (lastslash == NULL) + lastslash = strrchr (filename, ']'); + if (lastslash == NULL) + lastslash = strrchr (filename, '>'); + if (lastslash == NULL) + lastslash = strrchr (filename, ':'); +#endif +#ifdef HAVE_DOS_PATHS + /* Handle backslashes (possibly mixed with forward slashes) + and the case of "d:file". */ + { + char *bslash = strrchr (filename, '\\'); + if (lastslash == 0 || bslash > lastslash) + lastslash = bslash; + if (lastslash == 0 && filename[0] && filename[1] == ':') + lastslash = filename + 1; + } +#endif + if (lastslash != 0 && lastslash[1] == '\0') + lastslash = 0; + } + + pathlen = lastslash - filename + 1; + + /* First see which pattern rules match this target and may be considered. + Put them in TRYRULES. */ + + nrules = 0; + for (rule = pattern_rules; rule != 0; rule = rule->next) + { + unsigned int ti; + + /* If the pattern rule has deps but no commands, ignore it. + Users cancel built-in rules by redefining them without commands. */ + if (rule->deps != 0 && rule->cmds == 0) + continue; + + /* If this rule is in use by a parent pattern_search, + don't use it here. */ + if (rule->in_use) + { + DBS (DB_IMPLICIT, (_("Avoiding implicit rule recursion.\n"))); + continue; + } + + for (ti = 0; ti < rule->num; ++ti) + { + const char *target = rule->targets[ti]; + const char *suffix = rule->suffixes[ti]; + char check_lastslash; + + /* Rules that can match any filename and are not terminal + are ignored if we're recursing, so that they cannot be + intermediate files. */ + if (recursions > 0 && target[1] == '\0' && !rule->terminal) + continue; + + if (rule->lens[ti] > namelen) + /* It can't possibly match. */ + continue; + + /* From the lengths of the filename and the pattern parts, + find the stem: the part of the filename that matches the %. */ + stem = filename + (suffix - target - 1); + stemlen = namelen - rule->lens[ti] + 1; + + /* Set CHECK_LASTSLASH if FILENAME contains a directory + prefix and the target pattern does not contain a slash. */ + + check_lastslash = 0; + if (lastslash) + { +#ifdef VMS + check_lastslash = strpbrk (target, "/]>:") == NULL; +#else + check_lastslash = strchr (target, '/') == 0; +#endif +#ifdef HAVE_DOS_PATHS + /* Didn't find it yet: check for DOS-type directories. */ + if (check_lastslash) + { + char *b = strchr (target, '\\'); + check_lastslash = !(b || (target[0] && target[1] == ':')); + } +#endif + } + if (check_lastslash) + { + /* If so, don't include the directory prefix in STEM here. */ + if (pathlen > stemlen) + continue; + stemlen -= pathlen; + stem += pathlen; + } + + /* Check that the rule pattern matches the text before the stem. */ + if (check_lastslash) + { + if (stem > (lastslash + 1) + && !strneq (target, lastslash + 1, stem - lastslash - 1)) + continue; + } + else if (stem > filename + && !strneq (target, filename, stem - filename)) + continue; + + /* Check that the rule pattern matches the text after the stem. + We could test simply use streq, but this way we compare the + first two characters immediately. This saves time in the very + common case where the first character matches because it is a + period. */ + if (*suffix != stem[stemlen] + || (*suffix != '\0' && !streq (&suffix[1], &stem[stemlen + 1]))) + continue; + + /* Record if we match a rule that not all filenames will match. */ + if (target[1] != '\0') + specific_rule_matched = 1; + + /* A rule with no dependencies and no commands exists solely to set + specific_rule_matched when it matches. Don't try to use it. */ + if (rule->deps == 0 && rule->cmds == 0) + continue; + + /* Record this rule in TRYRULES and the index of the matching + target in MATCHES. If several targets of the same rule match, + that rule will be in TRYRULES more than once. */ + tryrules[nrules].rule = rule; + tryrules[nrules].matches = ti; + tryrules[nrules].stemlen = stemlen + (check_lastslash ? pathlen : 0); + tryrules[nrules].order = nrules; + tryrules[nrules].checked_lastslash = check_lastslash; + ++nrules; + } + } + + /* Bail out early if we haven't found any rules. */ + if (nrules == 0) + goto done; + + /* Sort the rules to place matches with the shortest stem first. This + way the most specific rules will be tried first. */ + if (nrules > 1) + qsort (tryrules, nrules, sizeof (struct tryrule), stemlen_compare); + + /* If we have found a matching rule that won't match all filenames, + retroactively reject any non-"terminal" rules that do always match. */ + if (specific_rule_matched) + for (ri = 0; ri < nrules; ++ri) + if (!tryrules[ri].rule->terminal) + { + unsigned int j; + for (j = 0; j < tryrules[ri].rule->num; ++j) + if (tryrules[ri].rule->targets[j][1] == '\0') + { + tryrules[ri].rule = 0; + break; + } + } + + /* Try each rule once without intermediate files, then once with them. */ + for (intermed_ok = 0; intermed_ok < 2; ++intermed_ok) + { + pat = deplist; + + /* Try each pattern rule till we find one that applies. If it does, + expand its dependencies (as substituted) and chain them in DEPS. */ + for (ri = 0; ri < nrules; ri++) + { + struct dep *dep; + char check_lastslash; + unsigned int failed = 0; + int file_variables_set = 0; + unsigned int deps_found = 0; + /* NPTR points to the part of the prereq we haven't processed. */ + const char *nptr = 0; + const char *dir = NULL; + int order_only = 0; + unsigned int matches; + + rule = tryrules[ri].rule; + + /* RULE is nil when we discover that a rule, already placed in + TRYRULES, should not be applied. */ + if (rule == 0) + continue; + + /* Reject any terminal rules if we're looking to make intermediate + files. */ + if (intermed_ok && rule->terminal) + continue; + + /* From the lengths of the filename and the matching pattern parts, + find the stem: the part of the filename that matches the %. */ + matches = tryrules[ri].matches; + stem = filename + (rule->suffixes[matches] + - rule->targets[matches]) - 1; + stemlen = (namelen - rule->lens[matches]) + 1; + check_lastslash = tryrules[ri].checked_lastslash; + if (check_lastslash) + { + stem += pathlen; + stemlen -= pathlen; + + /* We need to add the directory prefix, so set it up. */ + if (! pathdir) + { + pathdir = alloca (pathlen + 1); + memcpy (pathdir, filename, pathlen); + pathdir[pathlen] = '\0'; + } + dir = pathdir; + } + + if (stemlen > GET_PATH_MAX) + { + DBS (DB_IMPLICIT, (_("Stem too long: '%.*s'.\n"), + (int) stemlen, stem)); + continue; + } + + DBS (DB_IMPLICIT, (_("Trying pattern rule with stem '%.*s'.\n"), + (int) stemlen, stem)); + + strncpy (stem_str, stem, stemlen); + stem_str[stemlen] = '\0'; + + /* If there are no prerequisites, then this rule matches. */ + if (rule->deps == 0) + break; + + /* Temporary assign STEM to file->stem (needed to set file + variables below). */ + file->stem = stem_str; + + /* Mark this rule as in use so a recursive pattern_search won't try + to use it. */ + rule->in_use = 1; + + /* Try each prerequisite; see if it exists or can be created. We'll + build a list of prereq info in DEPLIST. Due to 2nd expansion we + may have to process multiple prereqs for a single dep entry. */ + + pat = deplist; + dep = rule->deps; + nptr = dep_name (dep); + while (1) + { + struct dep *dl, *d; + char *p; + + /* If we're out of name to parse, start the next prereq. */ + if (! nptr) + { + dep = dep->next; + if (dep == 0) + break; + nptr = dep_name (dep); + } + + /* If we don't need a second expansion, just replace the %. */ + if (! dep->need_2nd_expansion) + { + p = strchr (nptr, '%'); + if (p == 0) + strcpy (depname, nptr); + else + { + char *o = depname; + if (check_lastslash) + { + memcpy (o, filename, pathlen); + o += pathlen; + } + memcpy (o, nptr, p - nptr); + o += p - nptr; + memcpy (o, stem_str, stemlen); + o += stemlen; + strcpy (o, p + 1); + } + + /* Parse the expanded string. It might have wildcards. */ + p = depname; + dl = PARSE_SIMPLE_SEQ (&p, struct dep); + for (d = dl; d != NULL; d = d->next) + { + ++deps_found; + d->ignore_mtime = dep->ignore_mtime; + } + + /* We've used up this dep, so next time get a new one. */ + nptr = 0; + } + + /* We have to perform second expansion on this prereq. In an + ideal world we would take the dependency line, substitute the + stem, re-expand the whole line and chop it into individual + prerequisites. Unfortunately this won't work because of the + "check_lastslash" twist. Instead, we will have to go word by + word, taking $()'s into account. For each word we will + substitute the stem, re-expand, chop it up, and, if + check_lastslash != 0, add the directory part to each + resulting prerequisite. */ + else + { + int add_dir = 0; + unsigned int len; + struct dep **dptr; + + nptr = get_next_word (nptr, &len); + if (nptr == 0) + continue; + + /* See this is a transition to order-only prereqs. */ + if (! order_only && len == 1 && nptr[0] == '|') + { + order_only = 1; + nptr += len; + continue; + } + + /* If the dependency name has %, substitute the stem. If we + just replace % with the stem value then later, when we do + the 2nd expansion, we will re-expand this stem value + again. This is not good if you have certain characters + in your stem (like $). + + Instead, we will replace % with $* and allow the second + expansion to take care of it for us. This way (since $* + is a simple variable) there won't be additional + re-expansion of the stem. */ + + p = lindex (nptr, nptr + len, '%'); + if (p == 0) + { + memcpy (depname, nptr, len); + depname[len] = '\0'; + } + else + { + unsigned int i = p - nptr; + memcpy (depname, nptr, i); + memcpy (depname + i, "$*", 2); + memcpy (depname + i + 2, p + 1, len - i - 1); + depname[len + 2 - 1] = '\0'; + + if (check_lastslash) + add_dir = 1; + } + + /* Set up for the next word. */ + nptr += len; + + /* Initialize and set file variables if we haven't already + done so. */ + if (!file_vars_initialized) + { + initialize_file_variables (file, 0); +#if defined(CONFIG_WITH_COMMANDS_FUNC) || defined (CONFIG_WITH_DOT_MUST_MAKE) + set_file_variables (file, 0 /* real call */); +#else + set_file_variables (file); +#endif + file_vars_initialized = 1; + } + /* Update the stem value in $* for this rule. */ + else if (!file_variables_set) + { + define_variable_for_file ( + "*", 1, file->stem, o_automatic, 0, file); + file_variables_set = 1; + } + + /* Perform the 2nd expansion. */ + p = variable_expand_for_file (depname, file); + dptr = &dl; + + /* Parse the results into a deps list. */ + do + { + /* Parse the expanded string. */ + struct dep *dp = PARSE_FILE_SEQ (&p, struct dep, + order_only ? MAP_NUL : MAP_PIPE, + add_dir ? dir : NULL, PARSEFS_NONE); + *dptr = dp; + + for (d = dp; d != NULL; d = d->next) + { + ++deps_found; + if (order_only) + d->ignore_mtime = 1; + dptr = &d->next; + } + + /* If we stopped due to an order-only token, note it. */ + if (*p == '|') + { + order_only = 1; + ++p; + } + } + while (*p != '\0'); + } + + /* If there are more than max_pattern_deps prerequisites (due to + 2nd expansion), reset it and realloc the arrays. */ + + if (deps_found > max_deps) + { + unsigned int l = pat - deplist; + /* This might have changed due to recursion. */ + max_pattern_deps = MAX(max_pattern_deps, deps_found); + max_deps = max_pattern_deps; + deplist = xrealloc (deplist, + max_deps * sizeof (struct patdeps)); + pat = deplist + l; + } + + /* Go through the nameseq and handle each as a prereq name. */ + for (d = dl; d != 0; d = d->next) + { + struct dep *expl_d; + int is_rule = d->name == dep_name (dep); + + if (file_impossible_p (d->name)) + { + /* If this prereq has already been ruled "impossible", + then the rule fails. Don't bother trying it on the + second pass either since we know that will fail. */ + DBS (DB_IMPLICIT, + (is_rule + ? _("Rejecting impossible rule prerequisite '%s'.\n") + : _("Rejecting impossible implicit prerequisite '%s'.\n"), + d->name)); + tryrules[ri].rule = 0; + + failed = 1; + break; + } + + memset (pat, '\0', sizeof (struct patdeps)); + pat->ignore_mtime = d->ignore_mtime; + + DBS (DB_IMPLICIT, + (is_rule + ? _("Trying rule prerequisite '%s'.\n") + : _("Trying implicit prerequisite '%s'.\n"), d->name)); + + /* If this prereq is also explicitly mentioned for FILE, + skip all tests below since it must be built no matter + which implicit rule we choose. */ + + for (expl_d = file->deps; expl_d != 0; expl_d = expl_d->next) + if (streq (dep_name (expl_d), d->name)) + break; + if (expl_d != 0) + { + (pat++)->name = d->name; + continue; + } + + /* The DEP->changed flag says that this dependency resides + in a nonexistent directory. So we normally can skip + looking for the file. However, if CHECK_LASTSLASH is + set, then the dependency file we are actually looking for + is in a different directory (the one gotten by prepending + FILENAME's directory), so it might actually exist. */ + + /* @@ dep->changed check is disabled. */ + if (lookup_file (d->name) != 0 + /*|| ((!dep->changed || check_lastslash) && */ + || file_exists_p (d->name)) + { + (pat++)->name = d->name; + continue; + } + + /* This code, given FILENAME = "lib/foo.o", dependency name + "lib/foo.c", and VPATH=src, searches for + "src/lib/foo.c". */ + { + const char *vname = vpath_search (d->name, 0, NULL, NULL); + if (vname) + { + DBS (DB_IMPLICIT, + (_("Found prerequisite '%s' as VPATH '%s'\n"), + d->name, vname)); + (pat++)->name = d->name; + continue; + } + } + + /* We could not find the file in any place we should look. + Try to make this dependency as an intermediate file, but + only on the second pass. */ + + if (intermed_ok) + { + DBS (DB_IMPLICIT, + (_("Looking for a rule with intermediate file '%s'.\n"), + d->name)); + + if (int_file == 0) + int_file = alloca (sizeof (struct file)); + memset (int_file, '\0', sizeof (struct file)); + int_file->name = d->name; + + if (pattern_search (int_file, + 0, + depth + 1, + recursions + 1)) + { + pat->pattern = int_file->name; + int_file->name = d->name; + pat->file = int_file; + int_file = 0; + (pat++)->name = d->name; + continue; + } + + /* If we have tried to find P as an intermediate file + and failed, mark that name as impossible so we won't + go through the search again later. */ + if (int_file->variables) + free_variable_set (int_file->variables); + if (int_file->pat_variables) + free_variable_set (int_file->pat_variables); + file_impossible (d->name); + } + + /* A dependency of this rule does not exist. Therefore, this + rule fails. */ + failed = 1; + break; + } + + /* Free the ns chain. */ + free_dep_chain (dl); + + if (failed) + break; + } + + /* Reset the stem in FILE. */ + + file->stem = 0; + + /* This rule is no longer 'in use' for recursive searches. */ + rule->in_use = 0; + + if (! failed) + /* This pattern rule does apply. Stop looking for one. */ + break; + + /* This pattern rule does not apply. Keep looking. */ + } + + /* If we found an applicable rule without intermediate files, don't try + with them. */ + if (ri < nrules) + break; + + rule = 0; + } + + /* RULE is nil if the loop went through the list but everything failed. */ + if (rule == 0) + goto done; + + foundrule = ri; + + /* If we are recursing, store the pattern that matched FILENAME in + FILE->name for use in upper levels. */ + + if (recursions > 0) + /* Kludge-o-matic */ + file->name = rule->targets[tryrules[foundrule].matches]; + + /* DEPLIST lists the prerequisites for the rule we found. This includes the + intermediate files, if any. Convert them into entries on the deps-chain + of FILE. */ + + while (pat-- > deplist) + { + struct dep *dep; + const char *s; + + if (pat->file != 0) + { + /* If we need to use an intermediate file, make sure it is entered + as a target, with the info that was found for it in the recursive + pattern_search call. We know that the intermediate file did not + already exist as a target; therefore we can assume that the deps + and cmds of F below are null before we change them. */ + + struct file *imf = pat->file; + struct file *f = lookup_file (imf->name); + + /* We don't want to delete an intermediate file that happened + to be a prerequisite of some (other) target. Mark it as + secondary. We don't want it to be precious as that disables + DELETE_ON_ERROR etc. */ + if (f != 0) + f->secondary = 1; + else + f = enter_file (imf->name); + + f->deps = imf->deps; + f->cmds = imf->cmds; + f->stem = imf->stem; + f->variables = imf->variables; + f->pat_variables = imf->pat_variables; + f->pat_searched = imf->pat_searched; + f->also_make = imf->also_make; + f->is_target = 1; + f->intermediate = 1; + f->tried_implicit = 1; + + imf = lookup_file (pat->pattern); + if (imf != 0 && imf->precious) + f->precious = 1; + + for (dep = f->deps; dep != 0; dep = dep->next) + { + dep->file = enter_file (dep->name); + dep->name = 0; + dep->file->tried_implicit |= dep->changed; + } + } + + dep = alloc_dep (); + dep->ignore_mtime = pat->ignore_mtime; + s = strcache_add (pat->name); + if (recursions) + dep->name = s; + else + { + dep->file = lookup_file (s); + if (dep->file == 0) + dep->file = enter_file (s); + } + + if (pat->file == 0 && tryrules[foundrule].rule->terminal) + { + /* If the file actually existed (was not an intermediate file), and + the rule that found it was a terminal one, then we want to mark + the found file so that it will not have implicit rule search done + for it. If we are not entering a 'struct file' for it now, we + indicate this with the 'changed' flag. */ + if (dep->file == 0) + dep->changed = 1; + else + dep->file->tried_implicit = 1; + } + + dep->next = file->deps; + file->deps = dep; + } + + if (!tryrules[foundrule].checked_lastslash) + { + /* Always allocate new storage, since STEM might be on the stack for an + intermediate file. */ + file->stem = strcache_add_len (stem, stemlen); + fullstemlen = stemlen; + } + else + { + int dirlen = (lastslash + 1) - filename; + char *sp; + + /* We want to prepend the directory from + the original FILENAME onto the stem. */ + fullstemlen = dirlen + stemlen; + sp = alloca (fullstemlen + 1); + memcpy (sp, filename, dirlen); + memcpy (sp + dirlen, stem, stemlen); + sp[fullstemlen] = '\0'; +#ifndef CONFIG_WITH_VALUE_LENGTH + file->stem = strcache_add (sp); +#else + file->stem = strcache_add_len (sp, fullstemlen); +#endif + } + + file->cmds = rule->cmds; + file->is_target = 1; + + /* Set precious flag. */ + { + struct file *f = lookup_file (rule->targets[tryrules[foundrule].matches]); + if (f && f->precious) + file->precious = 1; + } + + /* If this rule builds other targets, too, put the others into FILE's + 'also_make' member. */ + + if (rule->num > 1) + for (ri = 0; ri < rule->num; ++ri) + if (ri != tryrules[foundrule].matches) + { + char *nm = alloca (rule->lens[ri] + fullstemlen + 1); + char *p = nm; + struct file *f; + struct dep *new = alloc_dep (); + + /* GKM FIMXE: handle '|' here too */ + memcpy (p, rule->targets[ri], + rule->suffixes[ri] - rule->targets[ri] - 1); + p += rule->suffixes[ri] - rule->targets[ri] - 1; + memcpy (p, file->stem, fullstemlen); + p += fullstemlen; + memcpy (p, rule->suffixes[ri], + rule->lens[ri] - (rule->suffixes[ri] - rule->targets[ri])+1); + new->name = strcache_add (nm); + new->file = enter_file (new->name); + new->next = file->also_make; + + /* Set precious flag. */ + f = lookup_file (rule->targets[ri]); + if (f && f->precious) + new->file->precious = 1; + + /* Set the is_target flag so that this file is not treated as + intermediate by the pattern rule search algorithm and + file_exists_p cannot pick it up yet. */ + new->file->is_target = 1; + + file->also_make = new; + } + + done: + free (tryrules); + free (deplist); + + return rule != 0; +} diff --git a/src/kmk/incdep.c b/src/kmk/incdep.c new file mode 100644 index 0000000..09de6ff --- /dev/null +++ b/src/kmk/incdep.c @@ -0,0 +1,2250 @@ +#ifdef CONFIG_WITH_INCLUDEDEP +/* $Id: incdep.c 3565 2022-05-24 20:40:24Z bird $ */ +/** @file + * incdep - Simple dependency files. + */ + +/* + * Copyright (c) 2007-2010 knut st. osmundsen + * + * This file is part of kBuild. + * + * kBuild is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * kBuild is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kBuild. If not, see + * + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#ifdef __OS2__ +# define INCL_BASE +# define INCL_ERRORS +#endif +#ifdef KBUILD_OS_WINDOWS +# ifdef KMK +# define INCDEP_USE_KFSCACHE +# endif +#endif + +#include "makeint.h" + +#if !defined(WINDOWS32) && !defined(__OS2__) +# define HAVE_PTHREAD +#endif + +#include + +#include + +#include "filedef.h" +#include "dep.h" +#include "job.h" +#include "commands.h" +#include "variable.h" +#include "rule.h" +#include "debug.h" +#include "strcache2.h" + +#ifdef HAVE_FCNTL_H +# include +#else +# include +#endif + +#ifdef WINDOWS32 +# include +# include +# include +# define PARSE_IN_WORKER +#endif + +#ifdef INCDEP_USE_KFSCACHE +# include "nt/kFsCache.h" +extern PKFSCACHE g_pFsCache; /* dir-nt-bird.c for now */ +#endif + +#ifdef __OS2__ +# include +# include +#endif + +#ifdef HAVE_PTHREAD +# include +#endif + +#ifdef __APPLE__ +# include +# define PARSE_IN_WORKER +#endif + +#if defined(__gnu_linux__) || defined(__linux__) +# define PARSE_IN_WORKER +#endif + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +struct incdep_variable_in_set +{ + struct incdep_variable_in_set *next; + /* the parameters */ + struct strcache2_entry *name_entry; /* dep strcache - WRONG */ + const char *value; /* xmalloc'ed */ + unsigned int value_length; + int duplicate_value; /* 0 */ + enum variable_origin origin; + int recursive; + struct variable_set *set; + const floc *flocp; /* NILF */ +}; + +struct incdep_variable_def +{ + struct incdep_variable_def *next; + /* the parameters */ + const floc *flocp; /* NILF */ + struct strcache2_entry *name_entry; /* dep strcache - WRONG */ + char *value; /* xmalloc'ed, free it */ + unsigned int value_length; + enum variable_origin origin; + enum variable_flavor flavor; + int target_var; +}; + +struct incdep_recorded_file +{ + struct incdep_recorded_file *next; + + /* the parameters */ + struct strcache2_entry *filename_entry; /* dep strcache; converted to a nameseq record. */ + struct dep *deps; /* All the names are dep strcache entries. */ + const floc *flocp; /* NILF */ +}; + + +/* per dep file structure. */ +struct incdep +{ + struct incdep *next; + char *file_base; + char *file_end; + + int worker_tid; +#ifdef PARSE_IN_WORKER + unsigned int err_line_no; + const char *err_msg; + + struct incdep_variable_in_set *recorded_variables_in_set_head; + struct incdep_variable_in_set *recorded_variables_in_set_tail; + + struct incdep_variable_def *recorded_variable_defs_head; + struct incdep_variable_def *recorded_variable_defs_tail; + + struct incdep_recorded_file *recorded_file_head; + struct incdep_recorded_file *recorded_file_tail; +#endif +#ifdef INCDEP_USE_KFSCACHE + /** Pointer to the fs cache object for this file (it exists and is a file). */ + PKFSOBJ pFileObj; +#else + char name[1]; +#endif +}; + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ + +/* mutex protecting the globals and an associated condition/event. */ +#ifdef HAVE_PTHREAD +static pthread_mutex_t incdep_mtx; +static pthread_cond_t incdep_cond_todo; +static pthread_cond_t incdep_cond_done; + +#elif defined (WINDOWS32) +static CRITICAL_SECTION incdep_mtx; +static HANDLE incdep_hev_todo; +static HANDLE incdep_hev_done; +static int volatile incdep_hev_todo_waiters; +static int volatile incdep_hev_done_waiters; + +#elif defined (__OS2__) +static _fmutex incdep_mtx; +static HEV incdep_hev_todo; +static HEV incdep_hev_done; +static int volatile incdep_hev_todo_waiters; +static int volatile incdep_hev_done_waiters; +#endif + +/* flag indicating whether the threads, lock and event/condvars has + been initialized or not. */ +static int incdep_initialized; + +/* the list of files that needs reading. */ +static struct incdep * volatile incdep_head_todo; +static struct incdep * volatile incdep_tail_todo; + +/* the number of files that are currently being read. */ +static int volatile incdep_num_reading; + +/* the list of files that have been read. */ +static struct incdep * volatile incdep_head_done; +static struct incdep * volatile incdep_tail_done; + + +/* The handles to the worker threads. */ +#ifdef HAVE_PTHREAD +# define INCDEP_MAX_THREADS 1 +static pthread_t incdep_threads[INCDEP_MAX_THREADS]; + +#elif defined (WINDOWS32) +# define INCDEP_MAX_THREADS 2 +static HANDLE incdep_threads[INCDEP_MAX_THREADS]; + +#elif defined (__OS2__) +# define INCDEP_MAX_THREADS 2 +static TID incdep_threads[INCDEP_MAX_THREADS]; +#endif + +static struct alloccache incdep_rec_caches[INCDEP_MAX_THREADS]; +static struct alloccache incdep_dep_caches[INCDEP_MAX_THREADS]; +static struct strcache2 incdep_dep_strcaches[INCDEP_MAX_THREADS]; +static struct strcache2 incdep_var_strcaches[INCDEP_MAX_THREADS]; +static unsigned incdep_num_threads; + +/* flag indicating whether the worker threads should terminate or not. */ +static int volatile incdep_terminate; + +#ifdef __APPLE__ +/* malloc zone for the incdep threads. */ +static malloc_zone_t *incdep_zone; +#endif + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +static void incdep_flush_it (floc *); +static void eval_include_dep_file (struct incdep *, floc *); +static void incdep_commit_recorded_file (const char *filename, struct dep *deps, + const floc *flocp); + + +/* xmalloc wrapper. + For working around multithreaded performance problems found on Darwin, + Linux (glibc), and possibly other systems. */ +static void * +incdep_xmalloc (struct incdep *cur, size_t size) +{ + void *ptr; + +#ifdef __APPLE__ + if (cur && cur->worker_tid != -1) + { + ptr = malloc_zone_malloc (incdep_zone, size); + if (!ptr) + O (fatal, NILF, _("virtual memory exhausted")); + } + else + ptr = xmalloc (size); +#else + ptr = xmalloc (size); +#endif + + (void)cur; + return ptr; +} + +#if 0 +/* cmalloc wrapper */ +static void * +incdep_xcalloc (struct incdep *cur, size_t size) +{ + void *ptr; + +#ifdef __APPLE__ + if (cur && cur->worker_tid != -1) + ptr = malloc_zone_calloc (incdep_zone, size, 1); + else + ptr = calloc (size, 1); +#else + ptr = calloc (size, 1); +#endif + if (!ptr) + fatal (NILF, _("virtual memory exhausted")); + + (void)cur; + return ptr; +} +#endif /* unused */ + +/* free wrapper */ +static void +incdep_xfree (struct incdep *cur, void *ptr) +{ + /* free() *must* work for the allocation hacks above because + of free_dep_chain. */ + free (ptr); + (void)cur; +} + +/* alloc a dep structure. These are allocated in bunches to save time. */ +struct dep * +incdep_alloc_dep (struct incdep *cur) +{ + struct alloccache *cache; + if (cur->worker_tid != -1) + cache = &incdep_dep_caches[cur->worker_tid]; + else + cache = &dep_cache; + return alloccache_calloc (cache); +} + +/* duplicates the dependency list pointed to by srcdep. */ +static struct dep * +incdep_dup_dep_list (struct incdep *cur, struct dep const *srcdep) +{ + struct alloccache *cache; + struct dep *retdep; + struct dep *dstdep; + + if (cur->worker_tid != -1) + cache = &incdep_dep_caches[cur->worker_tid]; + else + cache = &dep_cache; + + if (srcdep) + { + retdep = dstdep = alloccache_alloc (cache); + for (;;) + { + dstdep->name = srcdep->name; /* string cached */ + dstdep->includedep = srcdep->includedep; + srcdep = srcdep->next; + if (!srcdep) + { + dstdep->next = NULL; + break; + } + dstdep->next = alloccache_alloc (cache); + dstdep = dstdep->next; + } + } + else + retdep = NULL; + return retdep; +} + + +/* allocate a record. */ +static void * +incdep_alloc_rec (struct incdep *cur) +{ + return alloccache_alloc (&incdep_rec_caches[cur->worker_tid]); +} + +/* free a record. */ +static void +incdep_free_rec (struct incdep *cur, void *rec) +{ + /*alloccache_free (&incdep_rec_caches[cur->worker_tid], rec); - doesn't work of course. */ +} + + +/* grow a cache. */ +static void * +incdep_cache_allocator (void *thrd, unsigned int size) +{ + (void)thrd; +#ifdef __APPLE__ + return malloc_zone_malloc (incdep_zone, size); +#else + return xmalloc (size); +#endif +} + +/* term a cache. */ +static void +incdep_cache_deallocator (void *thrd, void *ptr, unsigned int size) +{ + (void)thrd; + (void)size; + free (ptr); +} + +/* acquires the lock */ +void +incdep_lock(void) +{ +#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) + pthread_mutex_lock (&incdep_mtx); +#elif defined (WINDOWS32) + EnterCriticalSection (&incdep_mtx); +#elif defined (__OS2__) + _fmutex_request (&incdep_mtx, 0); +#endif +} + +/* releases the lock */ +void +incdep_unlock(void) +{ +#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) + pthread_mutex_unlock (&incdep_mtx); +#elif defined(WINDOWS32) + LeaveCriticalSection (&incdep_mtx); +#elif defined(__OS2__) + _fmutex_release (&incdep_mtx); +#endif +} + +/* signals the main thread that there is stuff todo. caller owns the lock. */ +static void +incdep_signal_done (void) +{ +#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) + pthread_cond_broadcast (&incdep_cond_done); +#elif defined (WINDOWS32) + if (incdep_hev_done_waiters) + SetEvent (incdep_hev_done); +#elif defined (__OS2__) + if (incdep_hev_done_waiters) + DosPostEventSem (incdep_hev_done); +#endif +} + +/* waits for a reader to finish reading. caller owns the lock. */ +static void +incdep_wait_done (void) +{ +#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) + pthread_cond_wait (&incdep_cond_done, &incdep_mtx); + +#elif defined (WINDOWS32) + ResetEvent (incdep_hev_done); + incdep_hev_done_waiters++; + incdep_unlock (); + WaitForSingleObject (incdep_hev_done, INFINITE); + incdep_lock (); + incdep_hev_done_waiters--; + +#elif defined (__OS2__) + ULONG ulIgnore; + DosResetEventSem (incdep_hev_done, &ulIgnore); + incdep_hev_done_waiters++; + incdep_unlock (); + DosWaitEventSem (incdep_hev_done, SEM_INDEFINITE_WAIT); + incdep_lock (); + incdep_hev_done_waiters--; +#endif +} + +/* signals the worker threads. caller owns the lock. */ +static void +incdep_signal_todo (void) +{ +#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) + pthread_cond_broadcast (&incdep_cond_todo); +#elif defined(WINDOWS32) + if (incdep_hev_todo_waiters) + SetEvent (incdep_hev_todo); +#elif defined(__OS2__) + if (incdep_hev_todo_waiters) + DosPostEventSem (incdep_hev_todo); +#endif +} + +/* waits for stuff to arrive in the todo list. caller owns the lock. */ +static void +incdep_wait_todo (void) +{ +#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) + pthread_cond_wait (&incdep_cond_todo, &incdep_mtx); + +#elif defined (WINDOWS32) + ResetEvent (incdep_hev_todo); + incdep_hev_todo_waiters++; + incdep_unlock (); + WaitForSingleObject (incdep_hev_todo, INFINITE); + incdep_lock (); + incdep_hev_todo_waiters--; + +#elif defined (__OS2__) + ULONG ulIgnore; + DosResetEventSem (incdep_hev_todo, &ulIgnore); + incdep_hev_todo_waiters++; + incdep_unlock (); + DosWaitEventSem (incdep_hev_todo, SEM_INDEFINITE_WAIT); + incdep_lock (); + incdep_hev_todo_waiters--; +#endif +} + +/* Reads a dep file into memory. */ +static int +incdep_read_file (struct incdep *cur, floc *f) +{ +#ifdef INCDEP_USE_KFSCACHE + size_t const cbFile = (size_t)cur->pFileObj->Stats.st_size; + + assert(cur->pFileObj->fHaveStats); + cur->file_base = incdep_xmalloc (cur, cbFile + 1); + if (cur->file_base) + { + if (kFsCacheFileSimpleOpenReadClose (g_pFsCache, cur->pFileObj, 0, cur->file_base, cbFile)) + { + cur->file_end = cur->file_base + cbFile; + cur->file_base[cbFile] = '\0'; + return 0; + } + incdep_xfree (cur, cur->file_base); + } + OSS (error, f, "%s/%s: error reading file", cur->pFileObj->pParent->Obj.pszName, cur->pFileObj->pszName); + +#else /* !INCDEP_USE_KFSCACHE */ + int fd; + struct stat st; + + errno = 0; +# ifdef O_BINARY + fd = open (cur->name, O_RDONLY | O_BINARY, 0); +# else + fd = open (cur->name, O_RDONLY, 0); +# endif + if (fd < 0) + { + /* ignore non-existing dependency files. */ + int err = errno; + if (err == ENOENT || stat (cur->name, &st) != 0) + return 1; + OSS (error, f, "%s: %s", cur->name, strerror (err)); + return -1; + } +# ifdef KBUILD_OS_WINDOWS /* fewer kernel calls */ + if (!birdStatOnFdJustSize (fd, &st.st_size)) +# else + if (!fstat (fd, &st)) +# endif + { + cur->file_base = incdep_xmalloc (cur, st.st_size + 1); + if (read (fd, cur->file_base, st.st_size) == st.st_size) + { + close (fd); + cur->file_end = cur->file_base + st.st_size; + cur->file_base[st.st_size] = '\0'; + return 0; + } + + /* bail out */ + + OSS (error, f, "%s: read: %s", cur->name, strerror (errno)); + incdep_xfree (cur, cur->file_base); + } + else + OSS (error, f, "%s: fstat: %s", cur->name, strerror (errno)); + + close (fd); +#endif /* !INCDEP_USE_KFSCACHE */ + cur->file_base = cur->file_end = NULL; + return -1; +} + +/* Free the incdep structure. */ +static void +incdep_freeit (struct incdep *cur) +{ +#ifdef PARSE_IN_WORKER + assert (!cur->recorded_variables_in_set_head); + assert (!cur->recorded_variable_defs_head); + assert (!cur->recorded_file_head); +#endif + + incdep_xfree (cur, cur->file_base); +#ifdef INCDEP_USE_KFSCACHE + /** @todo release object ref some day... */ +#endif + cur->next = NULL; + free (cur); +} + +/* A worker thread. */ +void +incdep_worker (int thrd) +{ + incdep_lock (); + + while (!incdep_terminate) + { + /* get job from the todo list. */ + + struct incdep *cur = incdep_head_todo; + if (!cur) + { + incdep_wait_todo (); + continue; + } + if (cur->next) + incdep_head_todo = cur->next; + else + incdep_head_todo = incdep_tail_todo = NULL; + incdep_num_reading++; + + /* read the file. */ + + incdep_unlock (); + cur->worker_tid = thrd; + + incdep_read_file (cur, NILF); +#ifdef PARSE_IN_WORKER + eval_include_dep_file (cur, NILF); +#endif + + cur->worker_tid = -1; + incdep_lock (); + + /* insert finished job into the done list. */ + + incdep_num_reading--; + cur->next = NULL; + if (incdep_tail_done) + incdep_tail_done->next = cur; + else + incdep_head_done = cur; + incdep_tail_done = cur; + + incdep_signal_done (); + } + + incdep_unlock (); +} + +/* Thread library specific thread functions wrapping incdep_wroker. */ +#ifdef HAVE_PTHREAD +static void * +incdep_worker_pthread (void *thrd) +{ + incdep_worker ((size_t)thrd); + return NULL; +} + +#elif defined (WINDOWS32) +static unsigned __stdcall +incdep_worker_windows (void *thrd) +{ + incdep_worker ((size_t)thrd); + return 0; +} + +#elif defined (__OS2__) +static void +incdep_worker_os2 (void *thrd) +{ + incdep_worker ((size_t)thrd); +} +#endif + +/* Checks if threads are enabled or not. + + This is a special hack so that is possible to disable the threads when in a + debian fakeroot environment. Thus, in addition to the KMK_THREADS_DISABLED + and KMK_THREADS_ENABLED environment variable check we also check for signs + of fakeroot. */ +static int +incdep_are_threads_enabled (void) +{ +#if defined (CONFIG_WITHOUT_THREADS) + return 0; +#endif + + /* Generic overrides. */ + if (getenv ("KMK_THREADS_DISABLED")) + { + O (message, 1, "Threads disabled (environment)"); + return 0; + } + if (getenv ("KMK_THREADS_ENABLED")) + return 1; + +#if defined (__gnu_linux__) || defined (__linux__) || defined(__GLIBC__) + /* Try detect fakeroot. */ + if (getenv ("FAKEROOTKEY") + || getenv ("FAKEROOTUID") + || getenv ("FAKEROOTGID") + || getenv ("FAKEROOTEUID") + || getenv ("FAKEROOTEGID") + || getenv ("FAKEROOTSUID") + || getenv ("FAKEROOTSGID") + || getenv ("FAKEROOTFUID") + || getenv ("FAKEROOTFGID") + || getenv ("FAKEROOTDONTTRYCHOWN") + || getenv ("FAKEROOT_FD_BASE") + || getenv ("FAKEROOT_DB_SEARCH_PATHS")) + { + O (message, 1, "Threads disabled (fakeroot)"); + return 0; + } + + /* LD_PRELOAD could indicate undetected debian fakeroot or some + other ingenius library which cannot deal correctly with threads. */ + if (getenv ("LD_PRELOAD")) + { + O (message, 1, "Threads disabled (LD_PRELOAD)"); + return 0; + } + +#elif defined(__APPLE__) \ + || defined(__sun__) || defined(__SunOS__) || defined(__sun) || defined(__SunOS) \ + || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) \ + || defined(__HAIKU__) + /* No broken preload libraries known to be in common use on these platforms... */ + +#elif defined(_MSC_VER) || defined(_WIN32) || defined(__OS2__) + /* No preload mess to care about. */ + +#else +# error "Add your self to the appropriate case above and send a patch to bird." +#endif + return 1; +} + +/* Creates the the worker threads. */ +static void +incdep_init (floc *f) +{ + unsigned i; +#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) + int rc; + pthread_attr_t attr; + +#elif defined (WINDOWS32) + unsigned tid; + uintptr_t hThread; + +#elif defined (__OS2__) + int rc; + int tid; +#endif + (void)f; + + /* heap hacks */ + +#ifdef __APPLE__ + incdep_zone = malloc_create_zone (0, 0); + if (!incdep_zone) + incdep_zone = malloc_default_zone (); +#endif + + + /* create the mutex and two condition variables / event objects. */ + +#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) + rc = pthread_mutex_init (&incdep_mtx, NULL); + if (rc) + ON (fatal, f, _("pthread_mutex_init failed: err=%d"), rc); + rc = pthread_cond_init (&incdep_cond_todo, NULL); + if (rc) + ON (fatal, f, _("pthread_cond_init failed: err=%d"), rc); + rc = pthread_cond_init (&incdep_cond_done, NULL); + if (rc) + ON (fatal, f, _("pthread_cond_init failed: err=%d"), rc); + +#elif defined (WINDOWS32) + InitializeCriticalSection (&incdep_mtx); + incdep_hev_todo = CreateEvent (NULL, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL); + if (!incdep_hev_todo) + ON (fatal, f, _("CreateEvent failed: err=%d"), GetLastError()); + incdep_hev_done = CreateEvent (NULL, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL); + if (!incdep_hev_done) + ON (fatal, f, _("CreateEvent failed: err=%d"), GetLastError()); + incdep_hev_todo_waiters = 0; + incdep_hev_done_waiters = 0; + +#elif defined (__OS2__) + _fmutex_create (&incdep_mtx, 0); + rc = DosCreateEventSem (NULL, &incdep_hev_todo, 0, FALSE); + if (rc) + ON (fatal, f, _("DosCreateEventSem failed: rc=%d"), rc); + rc = DosCreateEventSem (NULL, &incdep_hev_done, 0, FALSE); + if (rc) + ON (fatal, f, _("DosCreateEventSem failed: rc=%d"), rc); + incdep_hev_todo_waiters = 0; + incdep_hev_done_waiters = 0; +#endif + + /* create the worker threads and associated per thread data. */ + + incdep_terminate = 0; + if (incdep_are_threads_enabled()) + { + incdep_num_threads = sizeof (incdep_threads) / sizeof (incdep_threads[0]); + if (incdep_num_threads + 1 > job_slots) + incdep_num_threads = job_slots <= 1 ? 1 : job_slots - 1; + for (i = 0; i < incdep_num_threads; i++) + { + /* init caches */ + unsigned rec_size = sizeof (struct incdep_variable_in_set); + if (rec_size < sizeof (struct incdep_variable_def)) + rec_size = sizeof (struct incdep_variable_def); + if (rec_size < sizeof (struct incdep_recorded_file)) + rec_size = sizeof (struct incdep_recorded_file); + alloccache_init (&incdep_rec_caches[i], rec_size, "incdep rec", + incdep_cache_allocator, (void *)(size_t)i); + alloccache_init (&incdep_dep_caches[i], sizeof(struct dep), "incdep dep", + incdep_cache_allocator, (void *)(size_t)i); + strcache2_init (&incdep_dep_strcaches[i], + "incdep dep", /* name */ + 65536, /* hash size */ + 0, /* default segment size*/ +#ifdef HAVE_CASE_INSENSITIVE_FS + 1, /* case insensitive */ +#else + 0, /* case insensitive */ +#endif + 0); /* thread safe */ + + strcache2_init (&incdep_var_strcaches[i], + "incdep var", /* name */ + 32768, /* hash size */ + 0, /* default segment size*/ + 0, /* case insensitive */ + 0); /* thread safe */ + + /* create the thread. */ +#if defined (HAVE_PTHREAD) && !defined (CONFIG_WITHOUT_THREADS) + rc = pthread_attr_init (&attr); + if (rc) + ON (fatal, f, _("pthread_attr_init failed: err=%d"), rc); + /*rc = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE); */ + rc = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + if (rc) + ON (fatal, f, _("pthread_attr_setdetachstate failed: err=%d"), rc); + rc = pthread_create (&incdep_threads[i], &attr, + incdep_worker_pthread, (void *)(size_t)i); + if (rc) + ON (fatal, f, _("pthread_mutex_init failed: err=%d"), rc); + pthread_attr_destroy (&attr); + +#elif defined (WINDOWS32) + tid = 0; + hThread = _beginthreadex (NULL, 128*1024, incdep_worker_windows, + (void *)i, 0, &tid); + if (hThread == 0 || hThread == ~(uintptr_t)0) + ON (fatal, f, _("_beginthreadex failed: err=%d"), errno); + incdep_threads[i] = (HANDLE)hThread; + +#elif defined (__OS2__) + tid = _beginthread (incdep_worker_os2, NULL, 128*1024, (void *)i); + if (tid <= 0) + ON (fatal, f, _("_beginthread failed: err=%d"), errno); + incdep_threads[i] = tid; +#endif + } + } + else + incdep_num_threads = 0; + + incdep_initialized = 1; +} + +/* Flushes outstanding work and terminates the worker threads. + This is called from snap_deps(). */ +void +incdep_flush_and_term (void) +{ + unsigned i; + + if (!incdep_initialized) + return; + + /* flush any out standing work */ + + incdep_flush_it (NILF); + + /* tell the threads to terminate */ + + incdep_lock (); + incdep_terminate = 1; + incdep_signal_todo (); + incdep_unlock (); + + /* wait for the threads to quit */ + + for (i = 0; i < incdep_num_threads; i++) + { + /* more later? */ + + /* terminate or join up the allocation caches. */ + alloccache_term (&incdep_rec_caches[i], incdep_cache_deallocator, (void *)(size_t)i); + alloccache_join (&dep_cache, &incdep_dep_caches[i]); + strcache2_term (&incdep_dep_strcaches[i]); + strcache2_term (&incdep_var_strcaches[i]); + } + incdep_num_threads = 0; + + /* destroy the lock and condition variables / event objects. */ + + /* later */ + + incdep_initialized = 0; +} + +#ifdef PARSE_IN_WORKER +/* Flushes a strcache entry returning the actual string cache entry. + The input is freed! */ +static const char * +incdep_flush_strcache_entry (struct strcache2_entry *entry) +{ + if (!entry->user) + entry->user = (void *) strcache2_add_hashed_file (&file_strcache, + (const char *)(entry + 1), + entry->length, entry->hash); + return (const char *)entry->user; +} + +/* Flushes the recorded instructions. */ +static void +incdep_flush_recorded_instructions (struct incdep *cur) +{ + struct incdep_variable_in_set *rec_vis; + struct incdep_variable_def *rec_vd; + struct incdep_recorded_file *rec_f; + + /* Display saved error. */ + + if (cur->err_msg) +#ifdef INCDEP_USE_KFSCACHE + OSSNS (error, NILF, "%s/%s(%d): %s", cur->pFileObj->pParent->Obj.pszName, cur->pFileObj->pszName, + cur->err_line_no, cur->err_msg); +#else + OSNS (error,NILF, "%s(%d): %s", cur->name, cur->err_line_no, cur->err_msg); +#endif + + + /* define_variable_in_set */ + + rec_vis = cur->recorded_variables_in_set_head; + cur->recorded_variables_in_set_head = cur->recorded_variables_in_set_tail = NULL; + if (rec_vis) + do + { + void *free_me = rec_vis; + unsigned int name_length = rec_vis->name_entry->length; + define_variable_in_set (incdep_flush_strcache_entry (rec_vis->name_entry), + name_length, + rec_vis->value, + rec_vis->value_length, + rec_vis->duplicate_value, + rec_vis->origin, + rec_vis->recursive, + rec_vis->set, + rec_vis->flocp); + rec_vis = rec_vis->next; + incdep_free_rec (cur, free_me); + } + while (rec_vis); + + /* do_variable_definition */ + + rec_vd = cur->recorded_variable_defs_head; + cur->recorded_variable_defs_head = cur->recorded_variable_defs_tail = NULL; + if (rec_vd) + do + { + void *free_me = rec_vd; + do_variable_definition_2 (rec_vd->flocp, + incdep_flush_strcache_entry (rec_vd->name_entry), + rec_vd->value, + rec_vd->value_length, + 0, + rec_vd->value, + rec_vd->origin, + rec_vd->flavor, + rec_vd->target_var); + rec_vd = rec_vd->next; + incdep_free_rec (cur, free_me); + } + while (rec_vd); + + /* record_files */ + + rec_f = cur->recorded_file_head; + cur->recorded_file_head = cur->recorded_file_tail = NULL; + if (rec_f) + do + { + void *free_me = rec_f; + struct dep *dep; + + for (dep = rec_f->deps; dep; dep = dep->next) + dep->name = incdep_flush_strcache_entry ((struct strcache2_entry *)dep->name); + + incdep_commit_recorded_file (incdep_flush_strcache_entry (rec_f->filename_entry), + rec_f->deps, + rec_f->flocp); + + rec_f = rec_f->next; + incdep_free_rec (cur, free_me); + } + while (rec_f); +} +#endif /* PARSE_IN_WORKER */ + +/* Record / issue a warning about a misformed dep file. */ +static void +incdep_warn (struct incdep *cur, unsigned int line_no, const char *msg) +{ + if (cur->worker_tid == -1) +#ifdef INCDEP_USE_KFSCACHE + OSSNS (error,NILF, "%s/%s(%d): %s", cur->pFileObj->pParent->Obj.pszName, cur->pFileObj->pszName, line_no, msg); +#else + OSNS (error, NILF, "%s(%d): %s", cur->name, line_no, msg); +#endif +#ifdef PARSE_IN_WORKER + else + { + cur->err_line_no = line_no; + cur->err_msg = msg; + } +#endif +} + +/* Dependency or file strcache allocation / recording. */ +static const char * +incdep_dep_strcache (struct incdep *cur, const char *str, int len) +{ + const char *ret; + if (cur->worker_tid == -1) + { + /* Make sure the string is terminated before we hand it to + strcache_add_len so it does have to make a temporary copy + of it on the stack. */ + char ch = str[len]; + ((char *)str)[len] = '\0'; + ret = strcache_add_len (str, len); + ((char *)str)[len] = ch; + } + else + { + /* Add it out the strcache of the thread. */ + ret = strcache2_add (&incdep_dep_strcaches[cur->worker_tid], str, len); + ret = (const char *)strcache2_get_entry(&incdep_dep_strcaches[cur->worker_tid], ret); + } + return ret; +} + +/* Variable name allocation / recording. */ +static const char * +incdep_var_strcache (struct incdep *cur, const char *str, int len) +{ + const char *ret; + if (cur->worker_tid == -1) + { + /* XXX: we're leaking this memory now! This will be fixed later. */ + ret = xmalloc (len + 1); + memcpy ((char *)ret, str, len); + ((char *)ret)[len] = '\0'; + } + else + { + /* Add it out the strcache of the thread. */ + ret = strcache2_add (&incdep_var_strcaches[cur->worker_tid], str, len); + ret = (const char *)strcache2_get_entry(&incdep_var_strcaches[cur->worker_tid], ret); + } + return ret; +} + +/* Record / perform a variable definition in a set. + The NAME is in the string cache. + The VALUE is on the heap. + The DUPLICATE_VALUE is always 0. */ +static void +incdep_record_variable_in_set (struct incdep *cur, + const char *name, unsigned int name_length, + const char *value, + unsigned int value_length, + int duplicate_value, + enum variable_origin origin, + int recursive, + struct variable_set *set, + const floc *flocp) +{ + assert (!duplicate_value); + if (cur->worker_tid == -1) + define_variable_in_set (name, name_length, value, value_length, + duplicate_value, origin, recursive, set, flocp); +#ifdef PARSE_IN_WORKER + else + { + struct incdep_variable_in_set *rec = + (struct incdep_variable_in_set *)incdep_alloc_rec (cur); + rec->name_entry = (struct strcache2_entry *)name; + rec->value = value; + rec->value_length = value_length; + rec->duplicate_value = duplicate_value; + rec->origin = origin; + rec->recursive = recursive; + rec->set = set; + rec->flocp = flocp; + + rec->next = NULL; + if (cur->recorded_variables_in_set_tail) + cur->recorded_variables_in_set_tail->next = rec; + else + cur->recorded_variables_in_set_head = rec; + cur->recorded_variables_in_set_tail = rec; + } +#endif +} + +/* Record / perform a variable definition. The VALUE should be disposed of. */ +static void +incdep_record_variable_def (struct incdep *cur, + const floc *flocp, + const char *name, + unsigned int name_length, + char *value, + unsigned int value_length, + enum variable_origin origin, + enum variable_flavor flavor, + int target_var) +{ + if (cur->worker_tid == -1) + do_variable_definition_2 (flocp, name, value, value_length, 0, value, + origin, flavor, target_var); +#ifdef PARSE_IN_WORKER + else + { + struct incdep_variable_def *rec = + (struct incdep_variable_def *)incdep_alloc_rec (cur); + rec->flocp = flocp; + rec->name_entry = (struct strcache2_entry *)name; + rec->value = value; + rec->value_length = value_length; + rec->origin = origin; + rec->flavor = flavor; + rec->target_var = target_var; + + rec->next = NULL; + if (cur->recorded_variable_defs_tail) + cur->recorded_variable_defs_tail->next = rec; + else + cur->recorded_variable_defs_head = rec; + cur->recorded_variable_defs_tail = rec; + } +#else + (void)name_length; +#endif +} + +/* Similar to record_files in read.c, only much much simpler. */ +static void +incdep_commit_recorded_file (const char *filename, struct dep *deps, + const floc *flocp) +{ + struct file *f; + + /* Perform some validations. */ + if (filename[0] == '.' + && ( streq(filename, ".POSIX") + || streq(filename, ".EXPORT_ALL_VARIABLES") + || streq(filename, ".INTERMEDIATE") + || streq(filename, ".LOW_RESOLUTION_TIME") + || streq(filename, ".NOTPARALLEL") + || streq(filename, ".ONESHELL") + || streq(filename, ".PHONY") + || streq(filename, ".PRECIOUS") + || streq(filename, ".SECONDARY") + || streq(filename, ".SECONDTARGETEXPANSION") + || streq(filename, ".SILENT") + || streq(filename, ".SHELLFLAGS") + || streq(filename, ".SUFFIXES") + ) + ) + { + OS (error, flocp, _("reserved filename '%s' used in dependency file, ignored"), filename); + return; + } + + /* Lookup or create an entry in the database. */ + f = enter_file (filename); + if (f->double_colon) + { + OS (error, flocp, _("dependency file '%s' has a double colon entry already, ignoring"), filename); + return; + } + f->is_target = 1; + + /* Append dependencies. */ + deps = enter_prereqs (deps, NULL); + if (deps) + { + struct dep *last = f->deps; + if (!last) + f->deps = deps; + else + { + while (last->next) + last = last->next; + last->next = deps; + } + } +} + +/* Record a file.*/ +static void +incdep_record_file (struct incdep *cur, + const char *filename, + struct dep *deps, + const floc *flocp) +{ + if (cur->worker_tid == -1) + incdep_commit_recorded_file (filename, deps, flocp); +#ifdef PARSE_IN_WORKER + else + { + struct incdep_recorded_file *rec = + (struct incdep_recorded_file *) incdep_alloc_rec (cur); + + rec->filename_entry = (struct strcache2_entry *)filename; + rec->deps = deps; + rec->flocp = flocp; + + rec->next = NULL; + if (cur->recorded_file_tail) + cur->recorded_file_tail->next = rec; + else + cur->recorded_file_head = rec; + cur->recorded_file_tail = rec; + } +#endif +} + +/* Counts slashes backwards from SLASH, stopping at START. */ +static size_t incdep_count_slashes_backwards(const char *slash, const char *start) +{ + size_t slashes = 1; + assert (*slash == '\\'); + while ((uintptr_t)slash > (uintptr_t)start && slash[0 - slashes] == '\\') + slashes++; + return slashes; +} + +/* Whitespace cannot be escaped at the end of a line, there has to be + some stuff following it other than a line continuation slash. + + So, we look ahead and makes sure that there is something non-whitespaced + following this allegedly escaped whitespace. + + This code ASSUMES the file content is zero terminated! */ +static int incdep_verify_escaped_whitespace(const char *ws) +{ + char ch; + + assert(ws[-1] == '\\'); + assert(ISBLANK((unsigned int)ws[0])); + + /* If the character following the '\ ' sequence is not a whitespace, + another escape character or null terminator, we're good. */ + ws += 2; + ch = *ws; + if (ch != '\\' && !ISSPACE((unsigned int)ch) && ch != '\0') + return 1; + + /* Otherwise we'll have to parse forward till we hit the end of the + line/file or something. */ + while ((ch = *ws++) != '\0') + { + if (ch == '\\') + { + /* escaped newline? */ + ch = *ws; + if (ch == '\n') + ws++; + else if (ch == '\r' && ws[1] == '\n') + ws += 2; + else + return 1; + } + else if (ISBLANK((unsigned int)ch)) + { /* contine */ } + else if (!ISSPACE((unsigned int)ch)) + return 1; + else + return 0; /* newline; all trailing whitespace will be ignored. */ + } + + return 0; +} + +/* Unescapes the next filename and returns cached copy. + + Modifies the input string that START points to. + + When NEXTP is not NULL, ASSUME target filename and that END isn't entirely + accurate in case the filename ends with a trailing backslash. There can be + more than one filename in a this case. NEXTP will be set to the first + character after then filename. + + When NEXTP is NULL, ASSUME exactly one dependency filename and that END is + accurately deliminating the string. + */ +static const char * +incdep_unescape_and_cache_filename(struct incdep *curdep, char *start, const char *end, + int const is_dep, const char **nextp, unsigned int *linenop) +{ + unsigned const esc_mask = MAP_BLANK /* ' ' + '\t' */ + | MAP_COLON /* ':' */ + | MAP_COMMENT /* '#' */ + | MAP_EQUALS /* '=' */ + | MAP_SEMI /* ';' */ + | ( is_dep + ? MAP_PIPE /* '|' */ + : MAP_PERCENT); /* '%' */ + unsigned const all_esc_mask = esc_mask | MAP_BLANK | MAP_NEWLINE; + unsigned const stop_mask = nextp ? MAP_BLANK | MAP_NEWLINE | (!is_dep ? MAP_COLON : 0) : 0; + char volatile *src; + char volatile *dst; + + /* + * Skip forward to the first escaped character so we can avoid unnecessary shifting. + */ +#if 1 + src = start; + dst = start; +#elif 1 + static const char s_szStop[] = "\n\r\t "; + + src = memchr(start, '$', end - start); + dst = memchr(start, '\\', end - start); + if (src && ((uintptr_t)src < (uintptr_t)dst || dst == NULL)) + dst = src; + else if (dst && ((uintptr_t)dst < (uintptr_t)src || src == NULL)) + src = dst; + else + { + assert(src == NULL && dst == NULL); + if (nextp) + { + int i = sizeof(s_szStop); + while (i-- > 0) + { + char *stop = memchr(start, s_szStop[i], end - start); + if (stop) + end = stop; + } + *nextp = end; + } + return incdep_dep_strcache (curdep, start, end - start); + } + if (nextp) + { + char *stop = src; + int i = sizeof(s_szStop); + while (i-- > 0) + { + char *stop2 = memchr(start, s_szStop[i], stop - start); + if (stop2) + stop = stop2; + } + if (stop != src) + { + *nextp = stop; + return incdep_dep_strcache (curdep, start, stop - start); + } + } +#endif + + /* + * Copy char-by-char, undoing escaping as we go along. + */ + while ((uintptr_t)src < (uintptr_t)end) + { + const char ch = *src++; + if (ch != '\\' && ch != '$') + { + if (!STOP_SET (ch, stop_mask)) + *dst++ = ch; + else + { + src--; + break; + } + } + else + { + char ch2 = *src++; /* No bounds checking to handle "/dir/file\ : ..." when end points at " :". */ + if (ch == '$') + { + if (ch2 != '$') /* $$ -> $ - Ignores secondary expansion! */ + src--; + *dst++ = ch; + } + else + { + unsigned int ch2_map; + + /* Eat all the slashes and see what's at the end of them as that's all + that's relevant. If there is an escapable char, we'll emit half of + the slashes. */ + size_t const max_slashes = src - start - 1; + size_t slashes = 1; + while (ch2 == '\\') + { + slashes++; + ch2 = *src++; + } + + /* Is it escapable? */ + ch2_map = stopchar_map[(unsigned char)ch2]; + if (ch2_map & all_esc_mask) + { + /* Non-whitespace is simple: Slash slashes, output or stop. */ + if (!(ch2_map & (MAP_BLANK | MAP_NEWLINE))) + { + assert(ch2_map & esc_mask); + while (slashes >= 2) + { + *dst++ = '\\'; + slashes -= 2; + } + if (slashes || !(stop_mask & ch2_map)) + *dst++ = ch2; + else + { + src--; + break; + } + } + /* Escaped blanks or newlines. + + We have to pretent that we've already replaced any escaped newlines + and associated whitespace with a single space here. We also have to + pretend trailing whitespace doesn't exist when IS_DEP is non-zero. + This makes for pretty interesting times... */ + else + { + char ch3; + + /* An Escaped blank is interesting because it is striped unconditionally + at the end of a line, regardless of how many escaped newlines may + following it. We join the escaped newline handling if we fine one + following us. */ + if (ch2_map & MAP_BLANK) + { + /* skip whitespace and check for escaped newline. */ + volatile char * const src_saved = src; + while ((ch3 = *src) != '\0' && ISBLANK(ch3)) + src++; + if (ch3 == '\\' && src[1] == '\n') + src += 2; /* Escaped blank & newline joins into single space. */ + else if (ch3 == '\\' && src[1] == '\r' && src[2] == '\n') + src += 3; /* -> Join the escaped newline code below on the next line. */ + else if (STOP_SET(ch3, stop_mask & MAP_NEWLINE)) + { /* last thing on the line, no blanks to escape. */ + while (slashes-- > 0) + *dst++ = '\\'; + break; + } + else + { + src = src_saved; + while (slashes >= 2) + { + *dst++ = '\\'; + slashes -= 2; + } + if (slashes) + { + *dst++ = ch2; + continue; + } + assert (nextp || (uintptr_t)src >= (uintptr_t)end); + break; + } + } + /* Escaped newlines get special treatment as they an any adjacent whitespace + gets reduced to a single space, including subsequent escaped newlines. + In addition, if this is the final dependency/file and there is no + significant new characters following this escaped newline, the replacement + space will also be stripped and we won't have anything to escape, meaning + that the slashes will remain as is. Finally, none of this space stuff can + be stop characters, unless of course a newline isn't escaped. */ + else + { + assert (ch2_map & MAP_NEWLINE); + if (ch2 == '\r' && *src == '\n') + src++; + } + + /* common space/newline code */ + for (;;) + { + if (linenop) + *linenop += 1; + while ((uintptr_t)src < (uintptr_t)end && ISBLANK(*src)) + src++; + if ((uintptr_t)src >= (uintptr_t)end) + { + ch3 = '\0'; + break; + } + ch3 = *src; + if (ch3 != '\\') + break; + ch3 = src[1]; + if (ch3 == '\n') + src += 2; + else if (ch3 == '\r' && src[2] == '\n') + src += 3; + else + break; + } + + if (is_dep && STOP_SET(ch3, stop_mask | MAP_NUL)) + { /* last thing on the line, no blanks to escape. */ + while (slashes-- > 0) + *dst++ = '\\'; + break; + } + while (slashes >= 2) + { + *dst++ = '\\'; + slashes -= 2; + } + if (slashes) + *dst++ = ' '; + else + { + assert (nextp || (uintptr_t)src >= (uintptr_t)end); + break; + } + } + } + /* Just output the slash if non-escapable character: */ + else + { + while (slashes-- > 0) + *dst++ = '\\'; + src--; + } + } + } + } + + if (nextp) + *nextp = (const char *)src; + return incdep_dep_strcache(curdep, start, dst - start); +} + +/* no nonsense dependency file including. + + Because nobody wants bogus dependency files to break their incremental + builds with hard to comprehend error messages, this function does not + use the normal eval routine but does all the parsing itself. This isn't, + as much work as it sounds, because the necessary feature set is very + limited. + + eval_include_dep_file groks: + + define var + endef + + var [|:|?|>]= value [\] + + [\] + file: [deps] [\] + + */ +static void +eval_include_dep_file (struct incdep *curdep, floc *f) +{ + unsigned line_no = 1; + const char *file_end = curdep->file_end; + const char *cur = curdep->file_base; + const char *endp; + + /* if no file data, just return immediately. */ + if (!cur) + return; + + /* now parse the file. */ + while ((uintptr_t)cur < (uintptr_t)file_end) + { + /* skip empty lines */ + while ((uintptr_t)cur < (uintptr_t)file_end && ISSPACE (*cur) && *cur != '\n') + ++cur; + if ((uintptr_t)cur >= (uintptr_t)file_end) + break; + if (*cur == '#') + { + cur = memchr (cur, '\n', file_end - cur); + if (!cur) + break; + } + if (*cur == '\\') + { + unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2 + : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3 + : (file_end - cur == 1) ? 1 : 0; + if (eol_len) + { + cur += eol_len; + line_no++; + continue; + } + } + if (*cur == '\n') + { + cur++; + line_no++; + continue; + } + + /* define var + ... + endef */ + if (strneq (cur, "define ", 7)) + { + const char *var; + unsigned var_len; + const char *value_start; + const char *value_end; + char *value; + unsigned value_len; + int found_endef = 0; + + /* extract the variable name. */ + cur += 7; + while (ISBLANK (*cur)) + ++cur; + value_start = endp = memchr (cur, '\n', file_end - cur); + if (!endp) + endp = cur; + while (endp > cur && ISSPACE (endp[-1])) + --endp; + var_len = endp - cur; + if (!var_len) + { + incdep_warn (curdep, line_no, "bogus define statement."); + break; + } + var = incdep_var_strcache (curdep, cur, var_len); + + /* find the end of the variable. */ + cur = value_end = value_start = value_start + 1; + ++line_no; + while ((uintptr_t)cur < (uintptr_t)file_end) + { + /* check for endef, don't bother with skipping leading spaces. */ + if ( file_end - cur >= 5 + && strneq (cur, "endef", 5)) + { + endp = cur + 5; + while ((uintptr_t)endp < (uintptr_t)file_end && ISSPACE (*endp) && *endp != '\n') + endp++; + if ((uintptr_t)endp >= (uintptr_t)file_end || *endp == '\n') + { + found_endef = 1; + cur = (uintptr_t)endp >= (uintptr_t)file_end ? file_end : endp + 1; + break; + } + } + + /* skip a line ahead. */ + cur = value_end = memchr (cur, '\n', file_end - cur); + if (cur != NULL) + ++cur; + else + cur = value_end = file_end; + ++line_no; + } + + if (!found_endef) + { + incdep_warn (curdep, line_no, "missing endef, dropping the rest of the file."); + break; + } + value_len = value_end - value_start; + if (memchr (value_start, '\0', value_len)) + { + incdep_warn (curdep, line_no, "'\\0' in define, dropping the rest of the file."); + break; + } + + /* make a copy of the value, converting \r\n to \n, and define it. */ + value = incdep_xmalloc (curdep, value_len + 1); + endp = memchr (value_start, '\r', value_len); + if (endp) + { + const char *src = value_start; + char *dst = value; + for (;;) + { + size_t len = endp - src; + memcpy (dst, src, len); + dst += len; + src = endp; + if ((uintptr_t)src + 1 < (uintptr_t)file_end && src[1] == '\n') + src++; /* skip the '\r' */ + if (src >= value_end) + break; + endp = memchr (endp + 1, '\r', src - value_end); + if (!endp) + endp = value_end; + } + value_len = dst - value; + } + else + memcpy (value, value_start, value_len); + value [value_len] = '\0'; + + incdep_record_variable_in_set (curdep, + var, var_len, value, value_len, + 0 /* don't duplicate */, o_file, + 0 /* defines are recursive but this is faster */, + NULL /* global set */, f); + } + + /* file: deps + OR + variable [:]= value */ + else + { + const char *equalp; + const char *eol; + + /* Look for a colon or an equal sign. In the assignment case, we + require it to be on the same line as the variable name to simplify + the code. Because of clang, we cannot make the same assumptions + with file dependencies. So, start with the equal. */ + + assert (*cur != '\n'); + eol = memchr (cur, '\n', file_end - cur); + if (!eol) + eol = file_end; + equalp = memchr (cur, '=', eol - cur); + if (equalp && equalp != cur && (ISSPACE(equalp[-1]) || equalp[-1] != '\\')) + { + /* An assignment of some sort. */ + const char *var; + unsigned var_len; + const char *value_start; + const char *value_end; + char *value; + unsigned value_len; + unsigned multi_line = 0; + enum variable_flavor flavor; + + /* figure the flavor first. */ + flavor = f_recursive; + if (equalp > cur) + { + if (equalp[-1] == ':') + flavor = f_simple; + else if (equalp[-1] == '?') + flavor = f_conditional; + else if (equalp[-1] == '+') + flavor = f_append; + else if (equalp[-1] == '>') + flavor = f_prepend; + } + + /* extract the variable name. */ + endp = flavor == f_recursive ? equalp : equalp - 1; + while (endp > cur && ISBLANK (endp[-1])) + --endp; + var_len = endp - cur; + if (!var_len) + { + incdep_warn (curdep, line_no, "empty variable. (includedep)"); + break; + } + if ( memchr (cur, '$', var_len) + || memchr (cur, ' ', var_len) + || memchr (cur, '\t', var_len)) + { + incdep_warn (curdep, line_no, "fancy variable name. (includedep)"); + break; + } + var = incdep_var_strcache (curdep, cur, var_len); + + /* find the start of the value. */ + cur = equalp + 1; + while ((uintptr_t)cur < (uintptr_t)file_end && ISBLANK (*cur)) + cur++; + value_start = cur; + + /* find the end of the value / line (this isn't 101% correct). */ + value_end = cur; + while ((uintptr_t)cur < (uintptr_t)file_end) + { + endp = value_end = memchr (cur, '\n', file_end - cur); + if (!value_end) + value_end = file_end; + if (value_end - 1 >= cur && value_end[-1] == '\r') + --value_end; + if (value_end - 1 < cur || value_end[-1] != '\\') + { + cur = endp ? endp + 1 : file_end; + break; + } + --value_end; + if (value_end - 1 >= cur && value_end[-1] == '\\') + { + incdep_warn (curdep, line_no, "fancy escaping! (includedep)"); + cur = NULL; + break; + } + if (!endp) + { + cur = file_end; + break; + } + + cur = endp + 1; + ++multi_line; + ++line_no; + } + if (!cur) + break; + ++line_no; + + /* make a copy of the value, converting \r\n to \n, and define it. */ + value_len = value_end - value_start; + value = incdep_xmalloc (curdep, value_len + 1); + if (!multi_line) + memcpy (value, value_start, value_len); + else + { + /* unescape it */ + const char *src = value_start; + char *dst = value; + while (src < value_end) + { + const char *nextp; + + endp = memchr (src, '\n', value_end - src); + if (!endp) + nextp = endp = value_end; + else + nextp = endp + 1; + if (endp > src && endp[-1] == '\r') + --endp; + if (endp > src && endp[-1] == '\\') + --endp; + + if (src != value_start) + *dst++ = ' '; + memcpy (dst, src, endp - src); + dst += endp - src; + src = nextp; + } + value_len = dst - value; + } + value [value_len] = '\0'; + + /* do the definition */ + if (flavor == f_recursive + || ( flavor == f_simple + && !memchr (value, '$', value_len))) + incdep_record_variable_in_set (curdep, + var, var_len, value, value_len, + 0 /* don't duplicate */, o_file, + flavor == f_recursive /* recursive */, + NULL /* global set */, f); + else + incdep_record_variable_def (curdep, + f, var, var_len, value, value_len, + o_file, flavor, 0 /* not target var */); + } + else + { + /* Expecting: file: dependencies */ + + int unescape_filename = 0; + const char *filename; + const char *fnnext; + const char *fnend; + const char *colonp; + struct dep *deps = 0; + struct dep **nextdep = &deps; + struct dep *dep; + + + /* Locate the next file colon. If it's not within the bounds of + the current line, check that all new line chars are escaped. */ + + colonp = memchr (cur, ':', file_end - cur); + while ( colonp + && ( ( colonp != cur + && colonp[-1] == '\\' + && incdep_count_slashes_backwards (&colonp[-1], cur) & 1) +#ifdef HAVE_DOS_PATHS + || ( colonp + 1 < file_end + && (colonp[1] == '/' || colonp[1] == '\\') + && colonp > cur + && isalpha ((unsigned char)colonp[-1]) + && ( colonp == cur + 1 + || ISBLANK ((unsigned char)colonp[-2]))) +#endif + ) + ) + colonp = memchr (colonp + 1, ':', file_end - (colonp + 1)); + if (!colonp) + { + incdep_warn (curdep, line_no, "no colon."); + break; + } + + if ((uintptr_t)colonp < (uintptr_t)eol) + unescape_filename = memchr (cur, '\\', colonp - cur) != NULL + || memchr (cur, '$', colonp - cur) != NULL; + else if (memchr (eol, '=', colonp - eol)) + { + incdep_warn (curdep, line_no, "multi line assignment / dependency confusion."); + break; + } + else + { + const char *sol = cur; + do + { + char *eol2 = (char *)eol - 1; + if ((uintptr_t)eol2 >= (uintptr_t)sol && *eol2 == '\r') /* DOS line endings. */ + eol2--; + if ((uintptr_t)eol2 < (uintptr_t)sol || *eol2 != '\\') + incdep_warn (curdep, line_no, "no colon."); + else if (eol2 != sol && eol2[-1] == '\\') + incdep_warn (curdep, line_no, "fancy EOL escape. (includedep)"); + else + { + line_no++; + sol = eol + 1; + eol = memchr (sol, '\n', colonp - sol); + continue; + } + sol = NULL; + break; + } + while (eol != NULL); + if (!sol) + break; + unescape_filename = 1; + } + + /* Extract the first filename after trimming and basic checks. */ + fnend = colonp; + while ((uintptr_t)fnend > (uintptr_t)cur && ISBLANK (fnend[-1])) + --fnend; + if (cur == fnend) + { + incdep_warn (curdep, line_no, "empty filename."); + break; + } + fnnext = cur; + if (!unescape_filename) + { + while (fnnext != fnend && !ISBLANK (*fnnext)) + fnnext++; + filename = incdep_dep_strcache (curdep, cur, fnnext - cur); + } + else + filename = incdep_unescape_and_cache_filename (curdep, (char *)fnnext, fnend, 0, &fnnext, NULL); + + /* parse any dependencies. */ + cur = colonp + 1; + while ((uintptr_t)cur < (uintptr_t)file_end) + { + const char *dep_file; + + /* skip blanks and count lines. */ + char ch = 0; + while ((uintptr_t)cur < (uintptr_t)file_end && ISSPACE ((ch = *cur)) && ch != '\n') + ++cur; + if ((uintptr_t)cur >= (uintptr_t)file_end) + break; + if (ch == '\n') + { + cur++; + line_no++; + break; + } + + /* continuation + eol? */ + if (ch == '\\') + { + unsigned eol_len = (file_end - cur > 1 && cur[1] == '\n') ? 2 + : (file_end - cur > 2 && cur[1] == '\r' && cur[2] == '\n') ? 3 + : (file_end - cur == 1) ? 1 : 0; + if (eol_len) + { + cur += eol_len; + line_no++; + continue; + } + } + + /* find the end of the filename and cache it */ + dep_file = NULL; + endp = cur; + for (;;) + if ((uintptr_t)endp < (uintptr_t)file_end) + { + ch = *endp; + if (ch != '\\' && ch != '$' ) + { + if (!ISSPACE (ch)) + endp++; + else + { + dep_file = incdep_dep_strcache(curdep, cur, endp - cur); + break; + } + } + else + { + /* potential escape sequence, let the unescaper do the rest. */ + dep_file = incdep_unescape_and_cache_filename (curdep, (char *)cur, file_end, 1, &endp, &line_no); + break; + } + } + else + { + dep_file = incdep_dep_strcache(curdep, cur, endp - cur); + break; + } + + /* add it to the list. */ + *nextdep = dep = incdep_alloc_dep (curdep); + dep->includedep = 1; + dep->name = dep_file; + nextdep = &dep->next; + + cur = endp; + } + + /* enter the file with its dependencies. */ + incdep_record_file (curdep, filename, deps, f); + + /* More files? Record them with the same dependency list. */ + if ((uintptr_t)fnnext < (uintptr_t)fnend) + for (;;) + { + const char *filename_prev = filename; + while (fnnext != fnend && ISBLANK (*fnnext)) + fnnext++; + if (fnnext == fnend) + break; + if (*fnnext == '\\') + { + if (fnnext[1] == '\n') + { + line_no++; + fnnext += 2; + continue; + } + if (fnnext[1] == '\r' && fnnext[2] == '\n') + { + line_no++; + fnnext += 3; + continue; + } + } + + if (!unescape_filename) + { + const char *fnstart = fnnext; + while (fnnext != fnend && !ISBLANK (*fnnext)) + fnnext++; + filename = incdep_dep_strcache (curdep, fnstart, fnnext - fnstart); + } + else + filename = incdep_unescape_and_cache_filename (curdep, (char *)fnnext, fnend, 0, &fnnext, NULL); + if (filename != filename_prev) /* clang optimization. */ + incdep_record_file (curdep, filename, incdep_dup_dep_list (curdep, deps), f); + } + } + } + } + + /* free the file data */ + incdep_xfree (curdep, curdep->file_base); + curdep->file_base = curdep->file_end = NULL; +} + +/* Flushes the incdep todo and done lists. */ +static void +incdep_flush_it (floc *f) +{ + incdep_lock (); + for (;;) + { + struct incdep *cur = incdep_head_done; + + /* if the done list is empty, grab a todo list entry. */ + if (!cur && incdep_head_todo) + { + cur = incdep_head_todo; + if (cur->next) + incdep_head_todo = cur->next; + else + incdep_head_todo = incdep_tail_todo = NULL; + incdep_unlock (); + + incdep_read_file (cur, f); + eval_include_dep_file (cur, f); + incdep_freeit (cur); + + incdep_lock (); + continue; + } + + /* if the todo list and done list are empty we're either done + or will have to wait for the thread(s) to finish. */ + if (!cur && !incdep_num_reading) + break; /* done */ + if (!cur) + { + while (!incdep_head_done) + incdep_wait_done (); + cur = incdep_head_done; + } + + /* we grab the entire done list and work thru it. */ + incdep_head_done = incdep_tail_done = NULL; + incdep_unlock (); + + while (cur) + { + struct incdep *next = cur->next; +#ifdef PARSE_IN_WORKER + incdep_flush_recorded_instructions (cur); +#else + eval_include_dep_file (cur, f); +#endif + incdep_freeit (cur); + cur = next; + } + + incdep_lock (); + } /* outer loop */ + incdep_unlock (); +} + + +/* splits up a list of file names and feeds it to eval_include_dep_file, + employing threads to try speed up the file reading. */ +void +eval_include_dep (const char *names, floc *f, enum incdep_op op) +{ + struct incdep *head = 0; + struct incdep *tail = 0; + struct incdep *cur; + const char *names_iterator = names; + const char *name; + unsigned int name_len; + + /* loop through NAMES, creating a todo list out of them. */ + + while ((name = find_next_token (&names_iterator, &name_len)) != 0) + { +#ifdef INCDEP_USE_KFSCACHE + KFSLOOKUPERROR enmError; + PKFSOBJ pFileObj = kFsCacheLookupWithLengthA (g_pFsCache, name, name_len, &enmError); + if (!pFileObj) + continue; + if (pFileObj->bObjType != KFSOBJ_TYPE_FILE) + { + kFsCacheObjRelease (g_pFsCache, pFileObj); + continue; + } + + cur = xmalloc (sizeof (*cur)); /* not incdep_xmalloc here */ + cur->pFileObj = pFileObj; +#else + cur = xmalloc (sizeof (*cur) + name_len); /* not incdep_xmalloc here */ + memcpy (cur->name, name, name_len); + cur->name[name_len] = '\0'; +#endif + + cur->file_base = cur->file_end = NULL; + cur->worker_tid = -1; +#ifdef PARSE_IN_WORKER + cur->err_line_no = 0; + cur->err_msg = NULL; + cur->recorded_variables_in_set_head = NULL; + cur->recorded_variables_in_set_tail = NULL; + cur->recorded_variable_defs_head = NULL; + cur->recorded_variable_defs_tail = NULL; + cur->recorded_file_head = NULL; + cur->recorded_file_tail = NULL; +#endif + + cur->next = NULL; + if (tail) + tail->next = cur; + else + head = cur; + tail = cur; + } + +#ifdef ELECTRIC_HEAP + if (1) +#else + if (op == incdep_read_it) +#endif + { + /* work our way thru the files directly */ + + cur = head; + while (cur) + { + struct incdep *next = cur->next; + incdep_read_file (cur, f); + eval_include_dep_file (cur, f); + incdep_freeit (cur); + cur = next; + } + } + else + { + /* initialize the worker threads and related stuff the first time around. */ + + if (!incdep_initialized) + incdep_init (f); + + /* queue the files and notify the worker threads. */ + + incdep_lock (); + + if (incdep_tail_todo) + incdep_tail_todo->next = head; + else + incdep_head_todo = head; + incdep_tail_todo = tail; + + incdep_signal_todo (); + incdep_unlock (); + + /* flush the todo queue if we're requested to do so. */ + + if (op == incdep_flush) + incdep_flush_it (f); + } +} + +#endif /* CONFIG_WITH_INCLUDEDEP */ + diff --git a/src/kmk/inlined_memchr.h b/src/kmk/inlined_memchr.h new file mode 100644 index 0000000..9666635 --- /dev/null +++ b/src/kmk/inlined_memchr.h @@ -0,0 +1,162 @@ +#define _GNU_SOURCE 1 +#include + +#ifdef _MSC_VER +_inline void * +#else +static __inline__ void * +#endif +my_inline_memchr(const void *pv, int ch, register size_t cb) +{ + register const unsigned int uch = (unsigned)ch; + register const unsigned char *pb = (const unsigned char *)pv; +#if 0 /* 8-byte loop unroll */ + while (cb >= 8) + { + if (*pb == uch) + return (unsigned char *)pb; + if (pb[1] == uch) + return (unsigned char *)pb + 1; + if (pb[2] == uch) + return (unsigned char *)pb + 2; + if (pb[3] == uch) + return (unsigned char *)pb + 3; + if (pb[4] == uch) + return (unsigned char *)pb + 4; + if (pb[5] == uch) + return (unsigned char *)pb + 5; + if (pb[6] == uch) + return (unsigned char *)pb + 6; + if (pb[7] == uch) + return (unsigned char *)pb + 7; + cb -= 8; + pb += 8; + } + switch (cb & 7) + { + case 0: + break; + case 1: + if (*pb == uch) + return (unsigned char *)pb; + break; + case 2: + if (*pb == uch) + return (unsigned char *)pb; + if (pb[1] == uch) + return (unsigned char *)pb + 1; + break; + case 3: + if (*pb == uch) + return (unsigned char *)pb; + if (pb[1] == uch) + return (unsigned char *)pb + 1; + if (pb[2] == uch) + return (unsigned char *)pb + 2; + break; + case 4: + if (*pb == uch) + return (unsigned char *)pb; + if (pb[1] == uch) + return (unsigned char *)pb + 1; + if (pb[2] == uch) + return (unsigned char *)pb + 2; + if (pb[3] == uch) + return (unsigned char *)pb + 3; + break; + case 5: + if (*pb == uch) + return (unsigned char *)pb; + if (pb[1] == uch) + return (unsigned char *)pb + 1; + if (pb[2] == uch) + return (unsigned char *)pb + 2; + if (pb[3] == uch) + return (unsigned char *)pb + 3; + if (pb[4] == uch) + return (unsigned char *)pb + 4; + break; + case 6: + if (*pb == uch) + return (unsigned char *)pb; + if (pb[1] == uch) + return (unsigned char *)pb + 1; + if (pb[2] == uch) + return (unsigned char *)pb + 2; + if (pb[3] == uch) + return (unsigned char *)pb + 3; + if (pb[4] == uch) + return (unsigned char *)pb + 4; + if (pb[5] == uch) + return (unsigned char *)pb + 5; + break; + case 7: + if (*pb == uch) + return (unsigned char *)pb; + if (pb[1] == uch) + return (unsigned char *)pb + 1; + if (pb[2] == uch) + return (unsigned char *)pb + 2; + if (pb[3] == uch) + return (unsigned char *)pb + 3; + if (pb[4] == uch) + return (unsigned char *)pb + 4; + if (pb[5] == uch) + return (unsigned char *)pb + 5; + if (pb[6] == uch) + return (unsigned char *)pb + 6; + break; + } + +#elif 1 /* 4 byte loop unroll */ + while (cb >= 4) + { + if (*pb == uch) + return (unsigned char *)pb; + if (pb[1] == uch) + return (unsigned char *)pb + 1; + if (pb[2] == uch) + return (unsigned char *)pb + 2; + if (pb[3] == uch) + return (unsigned char *)pb + 3; + cb -= 4; + pb += 4; + } + switch (cb & 3) + { + case 0: + break; + case 1: + if (*pb == uch) + return (unsigned char *)pb; + break; + case 2: + if (*pb == uch) + return (unsigned char *)pb; + if (pb[1] == uch) + return (unsigned char *)pb + 1; + break; + case 3: + if (*pb == uch) + return (unsigned char *)pb; + if (pb[1] == uch) + return (unsigned char *)pb + 1; + if (pb[2] == uch) + return (unsigned char *)pb + 2; + break; + } + +#else /* the basic loop */ + while (cb > 0) + { + if (*pb == uch) + return (void *)pb; + cb--; + pb++; + } +#endif + return 0; +} + +#define memchr my_inline_memchr + diff --git a/src/kmk/job.c b/src/kmk/job.c new file mode 100644 index 0000000..12d2ad3 --- /dev/null +++ b/src/kmk/job.c @@ -0,0 +1,3991 @@ +/* Job execution and handling for GNU Make. +Copyright (C) 1988-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#include "makeint.h" + +#include + +#include "job.h" +#include "debug.h" +#include "filedef.h" +#include "commands.h" +#include "variable.h" +#include "os.h" +#ifdef CONFIG_WITH_KMK_BUILTIN +# include "kmkbuiltin.h" +#endif +#ifdef KMK +# include "kbuild.h" +#endif + + +#include + +/* Default shell to use. */ +#ifdef WINDOWS32 +#include + +const char *default_shell = "sh.exe"; +int no_default_sh_exe = 1; +int batch_mode_shell = 1; +# ifndef CONFIG_NEW_WIN32_CTRL_EVENT +HANDLE main_thread; +# endif + +#elif defined (_AMIGA) + +const char *default_shell = ""; +extern int MyExecute (char **); +int batch_mode_shell = 0; + +#elif defined (__MSDOS__) + +/* The default shell is a pointer so we can change it if Makefile + says so. It is without an explicit path so we get a chance + to search the $PATH for it (since MSDOS doesn't have standard + directories we could trust). */ +const char *default_shell = "command.com"; +int batch_mode_shell = 0; + +#elif defined (__EMX__) + +const char *default_shell = "sh.exe"; /* bird changed this from "/bin/sh" as that doesn't make sense on OS/2. */ +int batch_mode_shell = 0; + +#elif defined (VMS) + +# include +# include +const char *default_shell = ""; +int batch_mode_shell = 0; + +#define strsignal vms_strsignal +char * vms_strsignal (int status); + +#ifndef C_FACILITY_NO +# define C_FACILITY_NO 0x350000 +#endif +#ifndef VMS_POSIX_EXIT_MASK +# define VMS_POSIX_EXIT_MASK (C_FACILITY_NO | 0xA000) +#endif + +#else + +const char *default_shell = "/bin/sh"; +int batch_mode_shell = 0; + +#endif + +#ifdef __MSDOS__ +# include +static int execute_by_shell; +static int dos_pid = 123; +int dos_status; +int dos_command_running; +#endif /* __MSDOS__ */ + +#ifdef _AMIGA +# include +static int amiga_pid = 123; +static int amiga_status; +static char amiga_bname[32]; +static int amiga_batch_file; +#endif /* Amiga. */ + +#ifdef VMS +# ifndef __GNUC__ +# include +# endif +# include +# include +static void vmsWaitForChildren (int *); +#endif + +#ifdef WINDOWS32 +# include +# include +# include +# ifdef CONFIG_NEW_WIN_CHILDREN +# include "w32/winchildren.h" +# else +# include "sub_proc.h" +# endif +# include "w32err.h" +# include "pathstuff.h" +# define WAIT_NOHANG 1 +#endif /* WINDOWS32 */ + +#ifdef __EMX__ +# include +#endif + +#if defined (HAVE_SYS_WAIT_H) || defined (HAVE_UNION_WAIT) +# include +#endif + +#ifdef HAVE_WAITPID +# define WAIT_NOHANG(status) waitpid (-1, (status), WNOHANG) +#else /* Don't have waitpid. */ +# ifdef HAVE_WAIT3 +# ifndef wait3 +extern int wait3 (); +# endif +# define WAIT_NOHANG(status) wait3 ((status), WNOHANG, (struct rusage *) 0) +# endif /* Have wait3. */ +#endif /* Have waitpid. */ + +#if !defined (wait) && !defined (POSIX) +int wait (); +#endif + +#ifndef HAVE_UNION_WAIT + +# define WAIT_T int + +# ifndef WTERMSIG +# define WTERMSIG(x) ((x) & 0x7f) +# endif +# ifndef WCOREDUMP +# define WCOREDUMP(x) ((x) & 0x80) +# endif +# ifndef WEXITSTATUS +# define WEXITSTATUS(x) (((x) >> 8) & 0xff) +# endif +# ifndef WIFSIGNALED +# define WIFSIGNALED(x) (WTERMSIG (x) != 0) +# endif +# ifndef WIFEXITED +# define WIFEXITED(x) (WTERMSIG (x) == 0) +# endif + +#else /* Have 'union wait'. */ + +# define WAIT_T union wait +# ifndef WTERMSIG +# define WTERMSIG(x) ((x).w_termsig) +# endif +# ifndef WCOREDUMP +# define WCOREDUMP(x) ((x).w_coredump) +# endif +# ifndef WEXITSTATUS +# define WEXITSTATUS(x) ((x).w_retcode) +# endif +# ifndef WIFSIGNALED +# define WIFSIGNALED(x) (WTERMSIG(x) != 0) +# endif +# ifndef WIFEXITED +# define WIFEXITED(x) (WTERMSIG(x) == 0) +# endif + +#endif /* Don't have 'union wait'. */ + +#if !defined(HAVE_UNISTD_H) && !defined(WINDOWS32) +# ifndef _MSC_VER /* bird */ +int dup2 (); +int execve (); +void _exit (); +# endif /* bird */ +# ifndef VMS +int geteuid (); +int getegid (); +int setgid (); +int getgid (); +# endif +#endif + +/* Different systems have different requirements for pid_t. + Plus we have to support gettext string translation... Argh. */ +static const char * +pid2str (pid_t pid) +{ + static char pidstring[100]; +#if defined(WINDOWS32) && (__GNUC__ > 3 || _MSC_VER > 1300) + /* %Id is only needed for 64-builds, which were not supported by + older versions of Windows compilers. */ + sprintf (pidstring, "%Id", pid); +#else + sprintf (pidstring, "%lu", (unsigned long) pid); +#endif + return pidstring; +} + +#ifndef HAVE_GETLOADAVG +int getloadavg (double loadavg[], int nelem); +#endif + +static void free_child (struct child *); +static void start_job_command (struct child *child); +static int load_too_high (void); +static int job_next_command (struct child *); +static int start_waiting_job (struct child *); +#ifdef CONFIG_WITH_PRINT_TIME_SWITCH +static void print_job_time (struct child *); +#endif + +/* Chain of all live (or recently deceased) children. */ + +struct child *children = 0; + +/* Number of children currently running. */ + +unsigned int job_slots_used = 0; + +/* Nonzero if the 'good' standard input is in use. */ + +static int good_stdin_used = 0; + +/* Chain of children waiting to run until the load average goes down. */ + +static struct child *waiting_jobs = 0; + +/* Non-zero if we use a *real* shell (always so on Unix). */ + +int unixy_shell = 1; + +/* Number of jobs started in the current second. */ + +unsigned long job_counter = 0; + +/* Number of jobserver tokens this instance is currently using. */ + +unsigned int jobserver_tokens = 0; + + +#ifdef WINDOWS32 +# ifndef CONFIG_NEW_WIN_CHILDREN /* (only used by commands.c) */ +/* + * The macro which references this function is defined in makeint.h. + */ +int +w32_kill (pid_t pid, int sig) +{ + return ((process_kill ((HANDLE)pid, sig) == TRUE) ? 0 : -1); +} +# endif /* !CONFIG_NEW_WIN_CHILDREN */ + +/* This function creates a temporary file name with an extension specified + * by the unixy arg. + * Return an xmalloc'ed string of a newly created temp file and its + * file descriptor, or die. */ +static char * +create_batch_file (char const *base, int unixy, int *fd) +{ + const char *const ext = unixy ? "sh" : "bat"; + const char *error_string = NULL; + char temp_path[MAXPATHLEN]; /* need to know its length */ + unsigned path_size = GetTempPath (sizeof temp_path, temp_path); + int path_is_dot = 0; + /* The following variable is static so we won't try to reuse a name + that was generated a little while ago, because that file might + not be on disk yet, since we use FILE_ATTRIBUTE_TEMPORARY below, + which tells the OS it doesn't need to flush the cache to disk. + If the file is not yet on disk, we might think the name is + available, while it really isn't. This happens in parallel + builds, where Make doesn't wait for one job to finish before it + launches the next one. */ + static unsigned uniq = 0; + static int second_loop = 0; + const unsigned sizemax = strlen (base) + strlen (ext) + 10; + + if (path_size == 0) + { + path_size = GetCurrentDirectory (sizeof temp_path, temp_path); + path_is_dot = 1; + } + + ++uniq; + if (uniq >= 0x10000 && !second_loop) + { + /* If we already had 64K batch files in this + process, make a second loop through the numbers, + looking for free slots, i.e. files that were + deleted in the meantime. */ + second_loop = 1; + uniq = 1; + } + while (path_size > 0 && + path_size + sizemax < sizeof temp_path && + !(uniq >= 0x10000 && second_loop)) + { + unsigned size = sprintf (temp_path + path_size, + "%s%s-%x.%s", + temp_path[path_size - 1] == '\\' ? "" : "\\", + base, uniq, ext); + HANDLE h = CreateFile (temp_path, /* file name */ + GENERIC_READ | GENERIC_WRITE, /* desired access */ + 0, /* no share mode */ + NULL, /* default security attributes */ + CREATE_NEW, /* creation disposition */ + FILE_ATTRIBUTE_NORMAL | /* flags and attributes */ + FILE_ATTRIBUTE_TEMPORARY, /* we'll delete it */ + NULL); /* no template file */ + + if (h == INVALID_HANDLE_VALUE) + { + const DWORD er = GetLastError (); + + if (er == ERROR_FILE_EXISTS || er == ERROR_ALREADY_EXISTS) + { + ++uniq; + if (uniq == 0x10000 && !second_loop) + { + second_loop = 1; + uniq = 1; + } + } + + /* the temporary path is not guaranteed to exist */ + else if (path_is_dot == 0) + { + path_size = GetCurrentDirectory (sizeof temp_path, temp_path); + path_is_dot = 1; + } + + else + { + error_string = map_windows32_error_to_string (er); + break; + } + } + else + { + const unsigned final_size = path_size + size + 1; + char *const path = xmalloc (final_size); + memcpy (path, temp_path, final_size); + *fd = _open_osfhandle ((intptr_t)h, 0); + if (unixy) + { + char *p; + int ch; + for (p = path; (ch = *p) != 0; ++p) + if (ch == '\\') + *p = '/'; + } + return path; /* good return */ + } + } + + *fd = -1; + if (error_string == NULL) + error_string = _("Cannot create a temporary file\n"); + O (fatal, NILF, error_string); + + /* not reached */ + return NULL; +} +#endif /* WINDOWS32 */ + +#ifdef __EMX__ +/* returns whether path is assumed to be a unix like shell. */ +int +_is_unixy_shell (const char *path) +{ + /* list of non unix shells */ + const char *known_os2shells[] = { + "cmd.exe", + "cmd", + "4os2.exe", + "4os2", + "4dos.exe", + "4dos", + "command.com", + "command", + NULL + }; + + /* find the rightmost '/' or '\\' */ + const char *name = strrchr (path, '/'); + const char *p = strrchr (path, '\\'); + unsigned i; + + if (name && p) /* take the max */ + name = (name > p) ? name : p; + else if (p) /* name must be 0 */ + name = p; + else if (!name) /* name and p must be 0 */ + name = path; + + if (*name == '/' || *name == '\\') name++; + + i = 0; + while (known_os2shells[i] != NULL) + { + if (strcasecmp (name, known_os2shells[i]) == 0) + return 0; /* not a unix shell */ + i++; + } + + /* in doubt assume a unix like shell */ + return 1; +} +#endif /* __EMX__ */ + +/* determines whether path looks to be a Bourne-like shell. */ +int +is_bourne_compatible_shell (const char *path) +{ + /* List of known POSIX (or POSIX-ish) shells. */ + static const char *unix_shells[] = { + "sh", + "bash", + "ksh", + "rksh", + "zsh", + "ash", + "dash", + NULL + }; + const char **s; + + /* find the rightmost '/' or '\\' */ + const char *name = strrchr (path, '/'); + char *p = strrchr (path, '\\'); + + if (name && p) /* take the max */ + name = (name > p) ? name : p; + else if (p) /* name must be 0 */ + name = p; + else if (!name) /* name and p must be 0 */ + name = path; + + if (*name == '/' || *name == '\\') + ++name; + + /* this should be able to deal with extensions on Windows-like systems */ + for (s = unix_shells; *s != NULL; ++s) + { +#if defined(WINDOWS32) || defined(__MSDOS__) + unsigned int len = strlen (*s); + if ((strlen (name) >= len && STOP_SET (name[len], MAP_DOT|MAP_NUL)) + && strncasecmp (name, *s, len) == 0) +#else + if (strcmp (name, *s) == 0) +#endif + return 1; /* a known unix-style shell */ + } + + /* if not on the list, assume it's not a Bourne-like shell */ + return 0; +} + + +/* Write an error message describing the exit status given in + EXIT_CODE, EXIT_SIG, and COREDUMP, for the target TARGET_NAME. + Append "(ignored)" if IGNORED is nonzero. */ + +static void +child_error (struct child *child, + int exit_code, int exit_sig, int coredump, int ignored) +{ + const char *pre = "*** "; + const char *post = ""; + const char *dump = ""; + const struct file *f = child->file; + const floc *flocp = &f->cmds->fileinfo; + const char *nm; + size_t l; + + if (ignored && silent_flag) + return; + + if (exit_sig && coredump) + dump = _(" (core dumped)"); + + if (ignored) + { + pre = ""; + post = _(" (ignored)"); + } + + if (! flocp->filenm) + nm = _(""); + else + { + char *a = alloca (strlen (flocp->filenm) + 1 + 11 + 1); + sprintf (a, "%s:%lu", flocp->filenm, flocp->lineno + flocp->offset); + nm = a; + } + + l = strlen (pre) + strlen (nm) + strlen (f->name) + strlen (post); + + OUTPUT_SET (&child->output); + + show_goal_error (); + + if (exit_sig == 0) +# if defined(KMK) && defined(KBUILD_OS_WINDOWS) + { + const char *exit_name = NULL; + switch ((unsigned)exit_code) + { + case 0xc0000005U: exit_name = "STATUS_ACCESS_VIOLATION"; break; + case 0xc000013aU: exit_name = "STATUS_CONTROL_C_EXIT"; break; + case 0xc0000374U: exit_name = "STATUS_HEAP_CORRUPTION"; break; + case 0xc0000409U: exit_name = "STATUS_STACK_BUFFER_OVERRUN"; break; + case 0xc0000417U: exit_name = "STATUS_INVALID_CRUNTIME_PARAMETER"; break; + case 0x80000003U: exit_name = "STATUS_BREAKPOINT"; break; + case 0x40000015U: exit_name = "STATUS_FATAL_APP_EXIT"; break; + case 0x40010004U: exit_name = "DBG_TERMINATE_PROCESS"; break; + case 0x40010005U: exit_name = "DBG_CONTROL_C"; break; + case 0x40010008U: exit_name = "DBG_CONTROL_BREAK"; break; + } + if (exit_name) + error (NILF, l + strlen (exit_name) + INTSTR_LENGTH, + _("%s[%s: %s] Error %d (%s)%s"), + pre, nm, f->name, exit_code, exit_name, post); + else + error (NILF, l + INTSTR_LENGTH + INTSTR_LENGTH, + _("%s[%s: %s] Error %d (%#x)%s"), + pre, nm, f->name, exit_code, exit_code, post); + } +# else + error (NILF, l + INTSTR_LENGTH, + _("%s[%s: %s] Error %d%s"), pre, nm, f->name, exit_code, post); +# endif + else + { + const char *s = strsignal (exit_sig); + error (NILF, l + strlen (s) + strlen (dump), + "%s[%s: %s] %s%s%s", pre, nm, f->name, s, dump, post); + } + + OUTPUT_UNSET (); +} + + +/* Handle a dead child. This handler may or may not ever be installed. + + If we're using the jobserver feature without pselect(), we need it. + First, installing it ensures the read will interrupt on SIGCHLD. Second, + we close the dup'd read FD to ensure we don't enter another blocking read + without reaping all the dead children. In this case we don't need the + dead_children count. + + If we don't have either waitpid or wait3, then make is unreliable, but we + use the dead_children count to reap children as best we can. */ + +static unsigned int dead_children = 0; + +RETSIGTYPE +child_handler (int sig UNUSED) +{ + ++dead_children; + + jobserver_signal (); + +#if defined __EMX__ && !defined(__INNOTEK_LIBC__) /* bird */ + /* The signal handler must called only once! */ + signal (SIGCHLD, SIG_DFL); +#endif +} + +extern pid_t shell_function_pid; + +/* Reap all dead children, storing the returned status and the new command + state ('cs_finished') in the 'file' member of the 'struct child' for the + dead child, and removing the child from the chain. In addition, if BLOCK + nonzero, we block in this function until we've reaped at least one + complete child, waiting for it to die if necessary. If ERR is nonzero, + print an error message first. */ + +void +reap_children (int block, int err) +{ +#ifndef WINDOWS32 + WAIT_T status; +#endif + /* Initially, assume we have some. */ + int reap_more = 1; + +#ifdef WAIT_NOHANG +# define REAP_MORE reap_more +#else +# define REAP_MORE dead_children +#endif + + /* As long as: + + We have at least one child outstanding OR a shell function in progress, + AND + We're blocking for a complete child OR there are more children to reap + + we'll keep reaping children. */ + + while ((children != 0 || shell_function_pid != 0) + && (block || REAP_MORE)) + { + unsigned int remote = 0; + pid_t pid; + int exit_code, exit_sig, coredump; + struct child *lastc, *c; + int child_failed; + int any_remote, any_local; + int dontcare; +#ifdef CONFIG_WITH_KMK_BUILTIN + struct child *completed_child = NULL; +#endif + + if (err && block) + { + static int printed = 0; + + /* We might block for a while, so let the user know why. + Only print this message once no matter how many jobs are left. */ + fflush (stdout); + if (!printed) + O (error, NILF, _("*** Waiting for unfinished jobs....")); + printed = 1; + } + + /* We have one less dead child to reap. As noted in + child_handler() above, this count is completely unimportant for + all modern, POSIX-y systems that support wait3() or waitpid(). + The rest of this comment below applies only to early, broken + pre-POSIX systems. We keep the count only because... it's there... + + The test and decrement are not atomic; if it is compiled into: + register = dead_children - 1; + dead_children = register; + a SIGCHLD could come between the two instructions. + child_handler increments dead_children. + The second instruction here would lose that increment. But the + only effect of dead_children being wrong is that we might wait + longer than necessary to reap a child, and lose some parallelism; + and we might print the "Waiting for unfinished jobs" message above + when not necessary. */ + + if (dead_children > 0) + --dead_children; + + any_remote = 0; + any_local = shell_function_pid != 0; + for (c = children; c != 0; c = c->next) + { + any_remote |= c->remote; + any_local |= ! c->remote; +#ifdef CONFIG_WITH_KMK_BUILTIN + if (c->has_status) + { + completed_child = c; + DB (DB_JOBS, (_("builtin child %p (%s) PID %s %s Status %ld\n"), + (void *)c, c->file->name, + pid2str (c->pid), c->remote ? _(" (remote)") : "", + (long) c->status)); + } + else +#endif + DB (DB_JOBS, (_("Live child %p (%s) PID %s %s\n"), + (void *)c, c->file->name, pid2str (c->pid), + c->remote ? _(" (remote)") : "")); +#ifdef VMS + break; +#endif + } + + /* First, check for remote children. */ + if (any_remote) + pid = remote_status (&exit_code, &exit_sig, &coredump, 0); + else + pid = 0; + + if (pid > 0) + /* We got a remote child. */ + remote = 1; + else if (pid < 0) + { + /* A remote status command failed miserably. Punt. */ + remote_status_lose: + pfatal_with_name ("remote_status"); + } + else + { + /* No remote children. Check for local children. */ +#ifdef CONFIG_WITH_KMK_BUILTIN + if (completed_child) + { + pid = completed_child->pid; +# if defined(WINDOWS32) + exit_code = completed_child->status; + exit_sig = 0; + coredump = 0; +# else + status = (WAIT_T)completed_child->status; +# endif + } + else +#endif /* CONFIG_WITH_KMK_BUILTIN */ +#if !defined(__MSDOS__) && !defined(_AMIGA) && !defined(WINDOWS32) + if (any_local) + { +#ifdef VMS + /* Todo: This needs more untangling multi-process support */ + /* Just do single child process support now */ + vmsWaitForChildren (&status); + pid = c->pid; + + /* VMS failure status can not be fully translated */ + status = $VMS_STATUS_SUCCESS (c->cstatus) ? 0 : (1 << 8); + + /* A Posix failure can be exactly translated */ + if ((c->cstatus & VMS_POSIX_EXIT_MASK) == VMS_POSIX_EXIT_MASK) + status = (c->cstatus >> 3 & 255) << 8; +#else +#ifdef WAIT_NOHANG + if (!block) + pid = WAIT_NOHANG (&status); + else +#endif + EINTRLOOP (pid, wait (&status)); +#endif /* !VMS */ + } + else + pid = 0; + + if (pid < 0) + { + /* The wait*() failed miserably. Punt. */ + pfatal_with_name ("wait"); + } + else if (pid > 0) + { + /* We got a child exit; chop the status word up. */ + exit_code = WEXITSTATUS (status); + exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0; + coredump = WCOREDUMP (status); + + /* If we have started jobs in this second, remove one. */ + if (job_counter) + --job_counter; + } + else + { + /* No local children are dead. */ + reap_more = 0; + + if (!block || !any_remote) + break; + + /* Now try a blocking wait for a remote child. */ + pid = remote_status (&exit_code, &exit_sig, &coredump, 1); + if (pid < 0) + goto remote_status_lose; + else if (pid == 0) + /* No remote children either. Finally give up. */ + break; + + /* We got a remote child. */ + remote = 1; + } +#endif /* !__MSDOS__, !Amiga, !WINDOWS32. */ + +#ifdef __MSDOS__ + /* Life is very different on MSDOS. */ + pid = dos_pid - 1; + status = dos_status; + exit_code = WEXITSTATUS (status); + if (exit_code == 0xff) + exit_code = -1; + exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0; + coredump = 0; +#endif /* __MSDOS__ */ +#ifdef _AMIGA + /* Same on Amiga */ + pid = amiga_pid - 1; + status = amiga_status; + exit_code = amiga_status; + exit_sig = 0; + coredump = 0; +#endif /* _AMIGA */ +#ifdef WINDOWS32 + { +# ifndef CONFIG_NEW_WIN_CHILDREN + HANDLE hPID; + HANDLE hcTID, hcPID; + DWORD dwWaitStatus = 0; + exit_code = 0; + exit_sig = 0; + coredump = 0; + +# ifndef CONFIG_NEW_WIN32_CTRL_EVENT + /* Record the thread ID of the main process, so that we + could suspend it in the signal handler. */ + if (!main_thread) + { + hcTID = GetCurrentThread (); + hcPID = GetCurrentProcess (); + if (!DuplicateHandle (hcPID, hcTID, hcPID, &main_thread, 0, + FALSE, DUPLICATE_SAME_ACCESS)) + { + DWORD e = GetLastError (); + fprintf (stderr, + "Determine main thread ID (Error %ld: %s)\n", + e, map_windows32_error_to_string (e)); + } + else + DB (DB_VERBOSE, ("Main thread handle = %p\n", main_thread)); + } +# endif + + /* wait for anything to finish */ + hPID = process_wait_for_any (block, &dwWaitStatus); + if (hPID) + { + /* was an error found on this process? */ + int werr = process_last_err (hPID); + + /* get exit data */ + exit_code = process_exit_code (hPID); + + if (werr) + fprintf (stderr, "make (e=%d): %s", exit_code, + map_windows32_error_to_string (exit_code)); + + /* signal */ + exit_sig = process_signal (hPID); + + /* cleanup process */ + process_cleanup (hPID); + + coredump = 0; + } + else if (dwWaitStatus == WAIT_FAILED) + { + /* The WaitForMultipleObjects() failed miserably. Punt. */ + pfatal_with_name ("WaitForMultipleObjects"); + } + else if (dwWaitStatus == WAIT_TIMEOUT) + { + /* No child processes are finished. Give up waiting. */ + reap_more = 0; + break; + } + + pid = (pid_t) hPID; +# else /* CONFIG_NEW_WIN_CHILDREN */ +# ifndef CONFIG_NEW_WIN32_CTRL_EVENT + /* Ctrl-C handler needs to suspend the main thread handle to + prevent mayhem when concurrently calling reap_children. */ + if ( !main_thread + && !DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), + GetCurrentProcess (), &main_thread, 0, + FALSE, DUPLICATE_SAME_ACCESS)) + fprintf (stderr, "Failed to duplicate main thread handle: %u\n", + GetLastError ()); +# endif + + assert (!any_remote); + pid = 0; + coredump = exit_sig = exit_code = 0; + { + int rc = MkWinChildWait(block, &pid, &exit_code, &exit_sig, &coredump, &c); + if (rc != 0) + ON (fatal, NILF, _("MkWinChildWait: %u"), rc); + } + if (pid == 0) + { + /* No more children, stop. */ + reap_more = 0; + break; + } + + /* If we have started jobs in this second, remove one. */ + if (job_counter) + --job_counter; +# endif /* CONFIG_NEW_WIN_CHILDREN */ + } +#endif /* WINDOWS32 */ + } + + /* Check if this is the child of the 'shell' function. */ + if (!remote && pid == shell_function_pid) + { + shell_completed (exit_code, exit_sig); + break; + } + + /* Search for a child matching the deceased one. */ + lastc = 0; + for (c = children; c != 0; lastc = c, c = c->next) + if (c->pid == pid && c->remote == remote) + break; + + if (c == 0) + /* An unknown child died. + Ignore it; it was inherited from our invoker. */ + continue; + + /* Determine the failure status: 0 for success, 1 for updating target in + question mode, 2 for anything else. */ + if (exit_sig == 0 && exit_code == 0) + child_failed = MAKE_SUCCESS; + else if (exit_sig == 0 && exit_code == 1 && question_flag && c->recursive) + child_failed = MAKE_TROUBLE; + else + child_failed = MAKE_FAILURE; + + DB (DB_JOBS, (child_failed + ? _("Reaping losing child %p PID %s %s\n") + : _("Reaping winning child %p PID %s %s\n"), + (void *)c, pid2str (c->pid), c->remote ? _(" (remote)") : "")); + + if (c->sh_batch_file) + { + int rm_status; + + DB (DB_JOBS, (_("Cleaning up temp batch file %s\n"), + c->sh_batch_file)); + + errno = 0; + rm_status = remove (c->sh_batch_file); + if (rm_status) + DB (DB_JOBS, (_("Cleaning up temp batch file %s failed (%d)\n"), + c->sh_batch_file, errno)); + + /* all done with memory */ + free (c->sh_batch_file); + c->sh_batch_file = NULL; + } + + /* If this child had the good stdin, say it is now free. */ + if (c->good_stdin) + good_stdin_used = 0; + + dontcare = c->dontcare; + + if (child_failed && !c->noerror && !ignore_errors_flag) + { + /* The commands failed. Write an error message, + delete non-precious targets, and abort. */ + static int delete_on_error = -1; + + if (!dontcare && child_failed == MAKE_FAILURE) +#ifdef KMK + { + child_error (c, exit_code, exit_sig, coredump, 0); + if ( ( c->file->cmds->lines_flags[c->command_line - 1] + & (COMMANDS_SILENT | COMMANDS_RECURSE)) + == COMMANDS_SILENT +# ifdef KBUILD_OS_WINDOWS /* show commands for NT statuses */ + || (exit_code & 0xc0000000) +# endif + || exit_sig != 0) + OS (message, 0, "The failing command:\n%s", c->file->cmds->command_lines[c->command_line - 1]); + } +#else /* !KMK */ + child_error (c, exit_code, exit_sig, coredump, 0); +#endif /* !KMK */ + + c->file->update_status = child_failed == MAKE_FAILURE ? us_failed : us_question; + if (delete_on_error == -1) + { + struct file *f = lookup_file (".DELETE_ON_ERROR"); + delete_on_error = f != 0 && f->is_target; + } + if (exit_sig != 0 || delete_on_error) + delete_child_targets (c); + } + else + { + if (child_failed) + { + /* The commands failed, but we don't care. */ + child_error (c, exit_code, exit_sig, coredump, 1); + child_failed = 0; + } + + /* If there are more commands to run, try to start them. */ + if (job_next_command (c)) + { + if (handling_fatal_signal) + { + /* Never start new commands while we are dying. + Since there are more commands that wanted to be run, + the target was not completely remade. So we treat + this as if a command had failed. */ + c->file->update_status = us_failed; + } + else + { +#ifndef NO_OUTPUT_SYNC + /* If we're sync'ing per line, write the previous line's + output before starting the next one. */ + if (output_sync == OUTPUT_SYNC_LINE) + output_dump (&c->output); +#endif + /* Check again whether to start remotely. + Whether or not we want to changes over time. + Also, start_remote_job may need state set up + by start_remote_job_p. */ + c->remote = start_remote_job_p (0); + start_job_command (c); + /* Fatal signals are left blocked in case we were + about to put that child on the chain. But it is + already there, so it is safe for a fatal signal to + arrive now; it will clean up this child's targets. */ + unblock_sigs (); + if (c->file->command_state == cs_running) + /* We successfully started the new command. + Loop to reap more children. */ + continue; + } + + if (c->file->update_status != us_success) + /* We failed to start the commands. */ + delete_child_targets (c); + } + else + /* There are no more commands. We got through them all + without an unignored error. Now the target has been + successfully updated. */ + c->file->update_status = us_success; + } + + /* When we get here, all the commands for c->file are finished. */ + +#ifndef NO_OUTPUT_SYNC + /* Synchronize any remaining parallel output. */ +# ifdef KMK + c->output.dont_truncate = !err && child_failed && !dontcare && !keep_going_flag && !handling_fatal_signal; +# endif + output_dump (&c->output); +#endif + + /* At this point c->file->update_status is success or failed. But + c->file->command_state is still cs_running if all the commands + ran; notice_finish_file looks for cs_running to tell it that + it's interesting to check the file's modtime again now. */ + + if (! handling_fatal_signal) + /* Notice if the target of the commands has been changed. + This also propagates its values for command_state and + update_status to its also_make files. */ + notice_finished_file (c->file); + + DB (DB_JOBS, (_("Removing child %p PID %s%s from chain.\n"), + (void *)c, pid2str (c->pid), c->remote ? _(" (remote)") : "")); + + /* Block fatal signals while frobnicating the list, so that + children and job_slots_used are always consistent. Otherwise + a fatal signal arriving after the child is off the chain and + before job_slots_used is decremented would believe a child was + live and call reap_children again. */ + block_sigs (); + + /* There is now another slot open. */ + if (job_slots_used > 0) + --job_slots_used; + + /* Remove the child from the chain and free it. */ + if (lastc == 0) + children = c->next; + else + lastc->next = c->next; + +#ifdef KMK /* Repeat the error */ + /* If the job failed, and the -k flag was not given, die, + unless we are already in the process of dying. */ + if (!err && child_failed && !dontcare && !keep_going_flag && + /* fatal_error_signal will die with the right signal. */ + !handling_fatal_signal) + { + unblock_sigs (); + die_with_job_output (child_failed, &c->output); + } +#endif + + free_child (c); + + unblock_sigs (); + +#ifndef KMK /* See above. */ + /* If the job failed, and the -k flag was not given, die, + unless we are already in the process of dying. */ + if (!err && child_failed && !dontcare && !keep_going_flag && + /* fatal_error_signal will die with the right signal. */ + !handling_fatal_signal) + die (child_failed); +#endif + + /* Only block for one child. */ + block = 0; + } + + return; +} + +/* Free the storage allocated for CHILD. */ + +static void +free_child (struct child *child) +{ +#ifdef CONFIG_WITH_PRINT_TIME_SWITCH + print_job_time (child); +#endif + output_close (&child->output); + + /* bird: Make sure the output_context doesn't point to a freed structure when + we return from this function. This is probably an issue elsewhere + in the code, however it doesn't cost us much fixing it here. (The + access after free was caught in a die() scenario, both in error + situations and successful ones.) */ + if (output_context == &child->output) + OUTPUT_UNSET(); + + if (!jobserver_tokens) + ONS (fatal, NILF, "INTERNAL: Freeing child %p (%s) but no tokens left!\n", + (void *)child, child->file->name); + + /* If we're using the jobserver and this child is not the only outstanding + job, put a token back into the pipe for it. */ + + if (jobserver_enabled () && jobserver_tokens > 1) + { + jobserver_release (1); + DB (DB_JOBS, (_("Released token for child %p (%s).\n"), + (void *)child, child->file->name)); + } + + --jobserver_tokens; + + if (handling_fatal_signal) /* Don't bother free'ing if about to die. */ + return; + + if (child->command_lines != 0) + { + register unsigned int i; + for (i = 0; i < child->file->cmds->ncommand_lines; ++i) + free (child->command_lines[i]); + free (child->command_lines); + } + + if (child->environment != 0) + { + register char **ep = child->environment; + while (*ep != 0) + free (*ep++); + free (child->environment); + } + +#ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS + /* Free the chopped command lines for simple targets when + there are no more active references to them. */ + + child->file->cmds->refs--; + if ( !child->file->intermediate + && !child->file->pat_variables) + free_chopped_commands(child->file->cmds); +#endif /* CONFIG_WITH_MEMORY_OPTIMIZATIONS */ + + free (child); +} + +#ifdef POSIX +extern sigset_t fatal_signal_set; +#endif + +void +block_sigs (void) +{ +#ifdef POSIX + (void) sigprocmask (SIG_BLOCK, &fatal_signal_set, (sigset_t *) 0); +#else +# ifdef HAVE_SIGSETMASK + (void) sigblock (fatal_signal_mask); +# endif +#endif +} + +#ifdef POSIX +void +unblock_sigs (void) +{ + sigset_t empty; + sigemptyset (&empty); + sigprocmask (SIG_SETMASK, &empty, (sigset_t *) 0); +} +#endif + +/* Start a job to run the commands specified in CHILD. + CHILD is updated to reflect the commands and ID of the child process. + + NOTE: On return fatal signals are blocked! The caller is responsible + for calling 'unblock_sigs', once the new child is safely on the chain so + it can be cleaned up in the event of a fatal signal. */ + +static void +start_job_command (struct child *child) +{ + int flags; + char *p; +#ifdef VMS + char *argv; +#else + char **argv; +#endif + + /* If we have a completely empty commandset, stop now. */ + if (!child->command_ptr) + goto next_command; + +#ifdef CONFIG_WITH_PRINT_TIME_SWITCH + if (child->start_ts == -1) + child->start_ts = nano_timestamp (); +#endif + + /* Combine the flags parsed for the line itself with + the flags specified globally for this target. */ + flags = (child->file->command_flags + | child->file->cmds->lines_flags[child->command_line - 1]); + + p = child->command_ptr; + child->noerror = ((flags & COMMANDS_NOERROR) != 0); + + while (*p != '\0') + { + if (*p == '@') + flags |= COMMANDS_SILENT; + else if (*p == '+') + flags |= COMMANDS_RECURSE; + else if (*p == '-') + child->noerror = 1; +#ifdef CONFIG_WITH_COMMANDS_FUNC + else if (*p == '%') + flags |= COMMAND_GETTER_SKIP_IT; +#endif + /* Don't skip newlines. */ + else if (!ISBLANK (*p)) +#ifndef CONFIG_WITH_KMK_BUILTIN + break; +#else /* CONFIG_WITH_KMK_BUILTIN */ + + { + if ( !(flags & COMMANDS_KMK_BUILTIN) + && !strncmp(p, "kmk_builtin_", sizeof("kmk_builtin_") - 1)) + flags |= COMMANDS_KMK_BUILTIN; + break; + } +#endif /* CONFIG_WITH_KMK_BUILTIN */ + ++p; + } + + child->recursive = ((flags & COMMANDS_RECURSE) != 0); + + /* Update the file's command flags with any new ones we found. We only + keep the COMMANDS_RECURSE setting. Even this isn't 100% correct; we are + now marking more commands recursive than should be in the case of + multiline define/endef scripts where only one line is marked "+". In + order to really fix this, we'll have to keep a lines_flags for every + actual line, after expansion. */ + child->file->cmds->lines_flags[child->command_line - 1] |= flags & COMMANDS_RECURSE; + + /* POSIX requires that a recipe prefix after a backslash-newline should + be ignored. Remove it now so the output is correct. */ + { + char prefix = child->file->cmds->recipe_prefix; + char *p1, *p2; + p1 = p2 = p; + while (*p1 != '\0') + { + *(p2++) = *p1; + if (p1[0] == '\n' && p1[1] == prefix) + ++p1; + ++p1; + } + *p2 = *p1; + } + + /* Figure out an argument list from this command line. */ + { + char *end = 0; +#ifdef VMS + /* Skip any leading whitespace */ + while (*p) + { + if (!ISSPACE (*p)) + { + if (*p != '\\') + break; + if ((p[1] != '\n') && (p[1] != 'n') && (p[1] != 't')) + break; + } + p++; + } + + argv = p; + /* Although construct_command_argv contains some code for VMS, it was/is + not called/used. Please note, for VMS argv is a string (not an array + of strings) which contains the complete command line, which for + multi-line variables still includes the newlines. So detect newlines + and set 'end' (which is used for child->command_ptr) instead of + (re-)writing construct_command_argv */ + if (!one_shell) + { + char *s = p; + int instring = 0; + while (*s) + { + if (*s == '"') + instring = !instring; + else if (*s == '\\' && !instring && *(s+1) != 0) + s++; + else if (*s == '\n' && !instring) + { + end = s; + break; + } + ++s; + } + } +#else + argv = construct_command_argv (p, &end, child->file, + child->file->cmds->lines_flags[child->command_line - 1], + &child->sh_batch_file); +#endif + if (end == NULL) + child->command_ptr = NULL; + else + { + *end++ = '\0'; + child->command_ptr = end; + } + } + + /* If -q was given, say that updating 'failed' if there was any text on the + command line, or 'succeeded' otherwise. The exit status of 1 tells the + user that -q is saying 'something to do'; the exit status for a random + error is 2. */ + if (argv != 0 && question_flag && !(flags & COMMANDS_RECURSE)) + { +#ifndef VMS + free (argv[0]); + free (argv); +#endif +#ifdef VMS + /* On VMS, argv[0] can be a null string here */ + if (argv[0] != 0) + { +#endif + child->file->update_status = us_question; + notice_finished_file (child->file); + return; +#ifdef VMS + } +#endif + } + + if (touch_flag && !(flags & COMMANDS_RECURSE)) + { + /* Go on to the next command. It might be the recursive one. + We construct ARGV only to find the end of the command line. */ +#ifndef VMS + if (argv) + { + free (argv[0]); + free (argv); + } +#endif + argv = 0; + } + + if (argv == 0) + { + next_command: +#ifdef __MSDOS__ + execute_by_shell = 0; /* in case construct_command_argv sets it */ +#endif + /* This line has no commands. Go to the next. */ + if (job_next_command (child)) + start_job_command (child); + else + { + /* No more commands. Make sure we're "running"; we might not be if + (e.g.) all commands were skipped due to -n. */ + set_command_state (child->file, cs_running); + child->file->update_status = us_success; + notice_finished_file (child->file); + } + + OUTPUT_UNSET(); + return; + } + + /* Are we going to synchronize this command's output? Do so if either we're + in SYNC_RECURSE mode or this command is not recursive. We'll also check + output_sync separately below in case it changes due to error. */ + child->output.syncout = output_sync && (output_sync == OUTPUT_SYNC_RECURSE + || !(flags & COMMANDS_RECURSE)); + OUTPUT_SET (&child->output); + +#ifndef NO_OUTPUT_SYNC + if (! child->output.syncout) + /* We don't want to sync this command: to avoid misordered + output ensure any already-synced content is written. */ + output_dump (&child->output); +#endif + + /* Print the command if appropriate. */ +#ifdef CONFIG_PRETTY_COMMAND_PRINTING + if ( pretty_command_printing + && (just_print_flag || (!(flags & COMMANDS_SILENT) && !silent_flag)) + && argv[0][0] != '\0') + { + unsigned i; + for (i = 0; argv[i]; i++) + OSSS ( message, 0, "%s'%s'%s", i ? "\t" : "> ", argv[i], argv[i + 1] ? " \\" : ""); + } + else +#endif /* CONFIG_PRETTY_COMMAND_PRINTING */ + if (just_print_flag || trace_flag + || (!(flags & COMMANDS_SILENT) && !silent_flag)) + OS (message, 0, "%s", p); + + /* Tell update_goal_chain that a command has been started on behalf of + this target. It is important that this happens here and not in + reap_children (where we used to do it), because reap_children might be + reaping children from a different target. We want this increment to + guaranteedly indicate that a command was started for the dependency + chain (i.e., update_file recursion chain) we are processing. */ + + ++commands_started; + + /* Optimize an empty command. People use this for timestamp rules, + so avoid forking a useless shell. Do this after we increment + commands_started so make still treats this special case as if it + performed some action (makes a difference as to what messages are + printed, etc. */ + +#if !defined(VMS) && !defined(_AMIGA) + if ( +#if defined __MSDOS__ || defined (__EMX__) + unixy_shell /* the test is complicated and we already did it */ +#else + (argv[0] && is_bourne_compatible_shell (argv[0])) +#endif + && (argv[1] && argv[1][0] == '-' + && + ((argv[1][1] == 'c' && argv[1][2] == '\0') + || + (argv[1][1] == 'e' && argv[1][2] == 'c' && argv[1][3] == '\0'))) + && (argv[2] && argv[2][0] == ':' && argv[2][1] == '\0') + && argv[3] == NULL) + { + free (argv[0]); + free (argv); + goto next_command; + } +#endif /* !VMS && !_AMIGA */ + + /* If -n was given, recurse to get the next line in the sequence. */ + + if (just_print_flag && !(flags & COMMANDS_RECURSE)) + { +#ifndef VMS + free (argv[0]); + free (argv); +#endif + goto next_command; + } + + /* We're sure we're going to invoke a command: set up the output. */ + output_start (); + + /* Flush the output streams so they won't have things written twice. */ + + fflush (stdout); + fflush (stderr); + +#ifdef CONFIG_WITH_KMK_BUILTIN + /* If builtin command then pass it on to the builtin shell interpreter. */ + + if ((flags & COMMANDS_KMK_BUILTIN) && !just_print_flag) + { + int rc; + char **argv_spawn = NULL; + char **p2 = argv; + while (*p2 && strncmp (*p2, "kmk_builtin_", sizeof("kmk_builtin_") - 1)) + p2++; + assert (*p2); + set_command_state (child->file, cs_running); + child->deleted = 0; + child->pid = 0; + if (p2 != argv) + rc = kmk_builtin_command (*p2, child, &argv_spawn, &child->pid); + else + { + int argc = 1; + while (argv[argc]) + argc++; + rc = kmk_builtin_command_parsed (argc, argv, child, &argv_spawn, &child->pid); + } + +# ifndef VMS + free (argv[0]); + free ((char *) argv); +# endif + + if (!rc) + { + /* spawned a child? */ + if (child->pid) + { + ++job_counter; + return; + } + + /* synchronous command execution? */ + if (!argv_spawn) + goto next_command; + } + + /* failure? */ + if (rc) + { + child->pid = (pid_t)42424242; + child->status = rc << 8; + child->has_status = 1; + unblock_sigs(); + return; + } + + /* conditional check == true; kicking off a child (not kmk_builtin_*). */ + argv = argv_spawn; + } +#endif /* CONFIG_WITH_KMK_BUILTIN */ + + /* Decide whether to give this child the 'good' standard input + (one that points to the terminal or whatever), or the 'bad' one + that points to the read side of a broken pipe. */ + + child->good_stdin = !good_stdin_used; + if (child->good_stdin) + good_stdin_used = 1; + + child->deleted = 0; + +#ifndef _AMIGA + /* Set up the environment for the child. */ + if (child->environment == 0) + child->environment = target_environment (child->file); +#endif + +#if !defined(__MSDOS__) && !defined(_AMIGA) && !defined(WINDOWS32) + +#ifndef VMS + /* start_waiting_job has set CHILD->remote if we can start a remote job. */ + if (child->remote) + { + int is_remote, id, used_stdin; + if (start_remote_job (argv, child->environment, + child->good_stdin ? 0 : get_bad_stdin (), + &is_remote, &id, &used_stdin)) + /* Don't give up; remote execution may fail for various reasons. If + so, simply run the job locally. */ + goto run_local; + else + { + if (child->good_stdin && !used_stdin) + { + child->good_stdin = 0; + good_stdin_used = 0; + } + child->remote = is_remote; + child->pid = id; + } + } + else +#endif /* !VMS */ + { + /* Fork the child process. */ + + char **parent_environ; + + run_local: + block_sigs (); + + child->remote = 0; + +#ifdef VMS + if (!child_execute_job (child, argv)) + { + /* Fork failed! */ + perror_with_name ("fork", ""); + goto error; + } + +#else + + parent_environ = environ; + + jobserver_pre_child (flags & COMMANDS_RECURSE); + + child->pid = child_execute_job (&child->output, child->good_stdin, argv, child->environment); + + environ = parent_environ; /* Restore value child may have clobbered. */ + jobserver_post_child (flags & COMMANDS_RECURSE); + + if (child->pid < 0) + { + /* Fork failed! */ + unblock_sigs (); + perror_with_name ("fork", ""); + goto error; + } +#endif /* !VMS */ + } + +#else /* __MSDOS__ or Amiga or WINDOWS32 */ +#ifdef __MSDOS__ + { + int proc_return; + + block_sigs (); + dos_status = 0; + + /* We call 'system' to do the job of the SHELL, since stock DOS + shell is too dumb. Our 'system' knows how to handle long + command lines even if pipes/redirection is needed; it will only + call COMMAND.COM when its internal commands are used. */ + if (execute_by_shell) + { + char *cmdline = argv[0]; + /* We don't have a way to pass environment to 'system', + so we need to save and restore ours, sigh... */ + char **parent_environ = environ; + + environ = child->environment; + + /* If we have a *real* shell, tell 'system' to call + it to do everything for us. */ + if (unixy_shell) + { + /* A *real* shell on MSDOS may not support long + command lines the DJGPP way, so we must use 'system'. */ + cmdline = argv[2]; /* get past "shell -c" */ + } + + dos_command_running = 1; + proc_return = system (cmdline); + environ = parent_environ; + execute_by_shell = 0; /* for the next time */ + } + else + { + dos_command_running = 1; + proc_return = spawnvpe (P_WAIT, argv[0], argv, child->environment); + } + + /* Need to unblock signals before turning off + dos_command_running, so that child's signals + will be treated as such (see fatal_error_signal). */ + unblock_sigs (); + dos_command_running = 0; + + /* If the child got a signal, dos_status has its + high 8 bits set, so be careful not to alter them. */ + if (proc_return == -1) + dos_status |= 0xff; + else + dos_status |= (proc_return & 0xff); + ++dead_children; + child->pid = dos_pid++; + } +#endif /* __MSDOS__ */ +#ifdef _AMIGA + amiga_status = MyExecute (argv); + + ++dead_children; + child->pid = amiga_pid++; + if (amiga_batch_file) + { + amiga_batch_file = 0; + DeleteFile (amiga_bname); /* Ignore errors. */ + } +#endif /* Amiga */ +#ifdef WINDOWS32 + { +# ifndef CONFIG_NEW_WIN_CHILDREN + HANDLE hPID; + char* arg0; + int outfd = FD_STDOUT; + int errfd = FD_STDERR; + + /* make UNC paths safe for CreateProcess -- backslash format */ + arg0 = argv[0]; + if (arg0 && arg0[0] == '/' && arg0[1] == '/') + for ( ; arg0 && *arg0; arg0++) + if (*arg0 == '/') + *arg0 = '\\'; + + /* make sure CreateProcess() has Path it needs */ + sync_Path_environment (); + +#ifndef NO_OUTPUT_SYNC + /* Divert child output if output_sync in use. */ + if (child->output.syncout) + { + if (child->output.out >= 0) + outfd = child->output.out; + if (child->output.err >= 0) + errfd = child->output.err; + } +#else + outfd = errfd = -1; +#endif + hPID = process_easy (argv, child->environment, outfd, errfd); + + if (hPID != INVALID_HANDLE_VALUE) + child->pid = (pid_t) hPID; + else + { + int i; + unblock_sigs (); + fprintf (stderr, + _("process_easy() failed to launch process (e=%ld)\n"), + process_last_err (hPID)); + for (i = 0; argv[i]; i++) + fprintf (stderr, "%s ", argv[i]); + fprintf (stderr, _("\nCounted %d args in failed launch\n"), i); + goto error; + } +# else /* CONFIG_NEW_WIN_CHILDREN */ + struct variable *shell_var = lookup_variable("SHELL", 5); + const char *shell_value = !shell_var ? NULL + : !shell_var->recursive || strchr(shell_var->value, '$') == NULL + ? shell_var->value : variable_expand (shell_var->value); + int rc = MkWinChildCreate(argv, child->environment, shell_value, child, &child->pid); + if (rc != 0) + { + int i; + unblock_sigs (); + fprintf (stderr, _("failed to launch process (rc=%d)\n"), rc); + for (i = 0; argv[i]; i++) + fprintf (stderr, "%s ", argv[i]); + fprintf (stderr, "\n", argv[i]); + goto error; + } +# endif /* CONFIG_NEW_WIN_CHILDREN */ + } +#endif /* WINDOWS32 */ +#endif /* __MSDOS__ or Amiga or WINDOWS32 */ + + /* Bump the number of jobs started in this second. */ + ++job_counter; + + /* We are the parent side. Set the state to + say the commands are running and return. */ + + set_command_state (child->file, cs_running); + + /* Free the storage used by the child's argument list. */ +#ifdef KMK /* leak */ + cleanup_argv: +#endif +#ifndef VMS + free (argv[0]); + free (argv); +#endif + + OUTPUT_UNSET(); + return; + + error: + child->file->update_status = us_failed; + notice_finished_file (child->file); +#ifdef KMK /* fix leak */ + goto cleanup_argv; +#else + OUTPUT_UNSET(); +#endif +} + +/* Try to start a child running. + Returns nonzero if the child was started (and maybe finished), or zero if + the load was too high and the child was put on the 'waiting_jobs' chain. */ + +static int +start_waiting_job (struct child *c) +{ + struct file *f = c->file; +#ifdef DB_KMK + DB (DB_KMK, (_("start_waiting_job %p (`%s') command_flags=%#x slots=%d/%d\n"), + (void *)c, c->file->name, c->file->command_flags, job_slots_used, job_slots)); +#endif + + /* If we can start a job remotely, we always want to, and don't care about + the local load average. We record that the job should be started + remotely in C->remote for start_job_command to test. */ + + c->remote = start_remote_job_p (1); + +#ifdef CONFIG_WITH_EXTENDED_NOTPARALLEL + if (c->file->command_flags & COMMANDS_NOTPARALLEL) + { + DB (DB_KMK, (_("not_parallel %d -> %d (file=%p `%s') [start_waiting_job]\n"), + not_parallel, not_parallel + 1, (void *)c->file, c->file->name)); + assert(not_parallel >= 0); + ++not_parallel; + } +#endif /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ + + /* If we are running at least one job already and the load average + is too high, make this one wait. */ + if (!c->remote +#ifdef CONFIG_WITH_EXTENDED_NOTPARALLEL + && ((job_slots_used > 0 && (not_parallel > 0 || load_too_high ())) +#else + && ((job_slots_used > 0 && load_too_high ()) +#endif +#ifdef WINDOWS32 +# ifndef CONFIG_NEW_WIN_CHILDREN + || (process_used_slots () >= MAXIMUM_WAIT_OBJECTS) +# endif +#endif + )) + { +#ifndef CONFIG_WITH_EXTENDED_NOTPARALLEL + /* Put this child on the chain of children waiting for the load average + to go down. */ + set_command_state (f, cs_running); + c->next = waiting_jobs; + waiting_jobs = c; + +#else /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ + + /* Put this child on the chain of children waiting for the load average + to go down. If not parallel, put it last. */ + set_command_state (f, cs_running); + c->next = waiting_jobs; + if (c->next && (c->file->command_flags & COMMANDS_NOTPARALLEL)) + { + struct child *prev = waiting_jobs; + while (prev->next) + prev = prev->next; + c->next = 0; + prev->next = c; + } + else /* FIXME: insert after the last node with COMMANDS_NOTPARALLEL set */ + waiting_jobs = c; + DB (DB_KMK, (_("queued child %p (`%s')\n"), (void *)c, c->file->name)); +#endif /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ + return 0; + } + + /* Start the first command; reap_children will run later command lines. */ + start_job_command (c); + + switch (f->command_state) + { + case cs_running: + c->next = children; + DB (DB_JOBS, (_("Putting child %p (%s) PID %s%s on the chain.\n"), + (void *)c, c->file->name, pid2str (c->pid), + c->remote ? _(" (remote)") : "")); + children = c; + /* One more job slot is in use. */ + ++job_slots_used; + unblock_sigs (); + break; + + case cs_not_started: + /* All the command lines turned out to be empty. */ + f->update_status = us_success; + /* FALLTHROUGH */ + + case cs_finished: + notice_finished_file (f); + free_child (c); + break; + + default: + assert (f->command_state == cs_finished); + break; + } + + return 1; +} + +/* Create a 'struct child' for FILE and start its commands running. */ + +void +new_job (struct file *file) +{ + struct commands *cmds = file->cmds; + struct child *c; + char **lines; + unsigned int i; + + /* Let any previously decided-upon jobs that are waiting + for the load to go down start before this new one. */ + start_waiting_jobs (); + + /* Reap any children that might have finished recently. */ + reap_children (0, 0); + + /* Chop the commands up into lines if they aren't already. */ + chop_commands (cmds); +#ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS + cmds->refs++; /* retain the chopped lines. */ +#endif + + /* Start the command sequence, record it in a new + 'struct child', and add that to the chain. */ + + c = xcalloc (sizeof (struct child)); + output_init (&c->output); + + c->file = file; + c->sh_batch_file = NULL; + + /* Cache dontcare flag because file->dontcare can be changed once we + return. Check dontcare inheritance mechanism for details. */ + c->dontcare = file->dontcare; + + /* Start saving output in case the expansion uses $(info ...) etc. */ + OUTPUT_SET (&c->output); + + /* Expand the command lines and store the results in LINES. */ + lines = xmalloc (cmds->ncommand_lines * sizeof (char *)); + for (i = 0; i < cmds->ncommand_lines; ++i) + { + /* Collapse backslash-newline combinations that are inside variable + or function references. These are left alone by the parser so + that they will appear in the echoing of commands (where they look + nice); and collapsed by construct_command_argv when it tokenizes. + But letting them survive inside function invocations loses because + we don't want the functions to see them as part of the text. */ + + char *in, *out, *ref; + + /* IN points to where in the line we are scanning. + OUT points to where in the line we are writing. + When we collapse a backslash-newline combination, + IN gets ahead of OUT. */ + + in = out = cmds->command_lines[i]; + while ((ref = strchr (in, '$')) != 0) + { + ++ref; /* Move past the $. */ + + if (out != in) + /* Copy the text between the end of the last chunk + we processed (where IN points) and the new chunk + we are about to process (where REF points). */ + memmove (out, in, ref - in); + + /* Move both pointers past the boring stuff. */ + out += ref - in; + in = ref; + + if (*ref == '(' || *ref == '{') + { + char openparen = *ref; + char closeparen = openparen == '(' ? ')' : '}'; + char *outref; + int count; + char *p; + + *out++ = *in++; /* Copy OPENPAREN. */ + outref = out; + /* IN now points past the opening paren or brace. + Count parens or braces until it is matched. */ + count = 0; + while (*in != '\0') + { + if (*in == closeparen && --count < 0) + break; + else if (*in == '\\' && in[1] == '\n') + { + /* We have found a backslash-newline inside a + variable or function reference. Eat it and + any following whitespace. */ + + int quoted = 0; + for (p = in - 1; p > ref && *p == '\\'; --p) + quoted = !quoted; + + if (quoted) + /* There were two or more backslashes, so this is + not really a continuation line. We don't collapse + the quoting backslashes here as is done in + collapse_continuations, because the line will + be collapsed again after expansion. */ + *out++ = *in++; + else + { + /* Skip the backslash, newline, and whitespace. */ + in += 2; + NEXT_TOKEN (in); + + /* Discard any preceding whitespace that has + already been written to the output. */ + while (out > outref && ISBLANK (out[-1])) + --out; + + /* Replace it all with a single space. */ + *out++ = ' '; + } + } + else + { + if (*in == openparen) + ++count; + + *out++ = *in++; + } + } + } + } + + /* There are no more references in this line to worry about. + Copy the remaining uninteresting text to the output. */ + if (out != in) + memmove (out, in, strlen (in) + 1); + + /* Finally, expand the line. */ + cmds->fileinfo.offset = i; + lines[i] = allocated_variable_expand_for_file (cmds->command_lines[i], + file); + } + + cmds->fileinfo.offset = 0; + c->command_lines = lines; +#ifdef CONFIG_WITH_PRINT_TIME_SWITCH + c->start_ts = -1; +#endif + + /* Fetch the first command line to be run. */ + job_next_command (c); + + /* Wait for a job slot to be freed up. If we allow an infinite number + don't bother; also job_slots will == 0 if we're using the jobserver. */ + + if (job_slots != 0) + while (job_slots_used == job_slots) + reap_children (1, 0); + +#ifdef MAKE_JOBSERVER + /* If we are controlling multiple jobs make sure we have a token before + starting the child. */ + + /* This can be inefficient. There's a decent chance that this job won't + actually have to run any subprocesses: the command script may be empty + or otherwise optimized away. It would be nice if we could defer + obtaining a token until just before we need it, in start_job_command. + To do that we'd need to keep track of whether we'd already obtained a + token (since start_job_command is called for each line of the job, not + just once). Also more thought needs to go into the entire algorithm; + this is where the old parallel job code waits, so... */ + + else if (jobserver_enabled ()) + while (1) + { + int got_token; + + DB (DB_JOBS, ("Need a job token; we %shave children\n", + children ? "" : "don't ")); + + /* If we don't already have a job started, use our "free" token. */ + if (!jobserver_tokens) + break; + + /* Prepare for jobserver token acquisition. */ + jobserver_pre_acquire (); + + /* Reap anything that's currently waiting. */ + reap_children (0, 0); + + /* Kick off any jobs we have waiting for an opportunity that + can run now (i.e., waiting for load). */ + start_waiting_jobs (); + + /* If our "free" slot is available, use it; we don't need a token. */ + if (!jobserver_tokens) + break; + + /* There must be at least one child already, or we have no business + waiting for a token. */ + if (!children) + O (fatal, NILF, "INTERNAL: no children as we go to sleep on read\n"); + + /* Get a token. */ + got_token = jobserver_acquire (waiting_jobs != NULL); + + /* If we got one, we're done here. */ + if (got_token == 1) + { + DB (DB_JOBS, (_("Obtained token for child %p (%s).\n"), + (void *)c, c->file->name)); + break; + } + } +#endif + + ++jobserver_tokens; + + /* Trace the build. + Use message here so that changes to working directories are logged. */ + if (trace_flag) + { + char *newer = allocated_variable_expand_for_file ("$?", c->file); + const char *nm; + + if (! cmds->fileinfo.filenm) + nm = _(""); + else + { + char *n = alloca (strlen (cmds->fileinfo.filenm) + 1 + 11 + 1); + sprintf (n, "%s:%lu", cmds->fileinfo.filenm, cmds->fileinfo.lineno); + nm = n; + } + + if (newer[0] == '\0') + OSS (message, 0, + _("%s: target '%s' does not exist"), nm, c->file->name); + else + OSSS (message, 0, + _("%s: update target '%s' due to: %s"), nm, c->file->name, newer); + + free (newer); + } + + /* The job is now primed. Start it running. + (This will notice if there is in fact no recipe.) */ + start_waiting_job (c); + +#ifndef CONFIG_WITH_EXTENDED_NOTPARALLEL + if (job_slots == 1 || not_parallel) + /* Since there is only one job slot, make things run linearly. + Wait for the child to die, setting the state to 'cs_finished'. */ + while (file->command_state == cs_running) + reap_children (1, 0); + +#else /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ + + if (job_slots == 1 || not_parallel < 0) + { + /* Since there is only one job slot, make things run linearly. + Wait for the child to die, setting the state to `cs_finished'. */ + while (file->command_state == cs_running) + reap_children (1, 0); + } + else if (not_parallel > 0) + { + /* wait for all live children to finish and then continue + with the not-parallel child(s). FIXME: this loop could be better? */ + while (file->command_state == cs_running + && (children != 0 || shell_function_pid != 0) /* reap_child condition */ + && not_parallel > 0) + reap_children (1, 0); + } +#endif /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ + + OUTPUT_UNSET (); + return; +} + +/* Move CHILD's pointers to the next command for it to execute. + Returns nonzero if there is another command. */ + +static int +job_next_command (struct child *child) +{ + while (child->command_ptr == 0 || *child->command_ptr == '\0') + { + /* There are no more lines in the expansion of this line. */ + if (child->command_line == child->file->cmds->ncommand_lines) + { + /* There are no more lines to be expanded. */ + child->command_ptr = 0; + child->file->cmds->fileinfo.offset = 0; + return 0; + } + else + /* Get the next line to run. */ + child->command_ptr = child->command_lines[child->command_line++]; + } + + child->file->cmds->fileinfo.offset = child->command_line - 1; + return 1; +} + +/* Determine if the load average on the system is too high to start a new job. + The real system load average is only recomputed once a second. However, a + very parallel make can easily start tens or even hundreds of jobs in a + second, which brings the system to its knees for a while until that first + batch of jobs clears out. + + To avoid this we use a weighted algorithm to try to account for jobs which + have been started since the last second, and guess what the load average + would be now if it were computed. + + This algorithm was provided by Thomas Riedl , + who writes: + +! calculate something load-oid and add to the observed sys.load, +! so that latter can catch up: +! - every job started increases jobctr; +! - every dying job decreases a positive jobctr; +! - the jobctr value gets zeroed every change of seconds, +! after its value*weight_b is stored into the 'backlog' value last_sec +! - weight_a times the sum of jobctr and last_sec gets +! added to the observed sys.load. +! +! The two weights have been tried out on 24 and 48 proc. Sun Solaris-9 +! machines, using a several-thousand-jobs-mix of cpp, cc, cxx and smallish +! sub-shelled commands (rm, echo, sed...) for tests. +! lowering the 'direct influence' factor weight_a (e.g. to 0.1) +! resulted in significant excession of the load limit, raising it +! (e.g. to 0.5) took bad to small, fast-executing jobs and didn't +! reach the limit in most test cases. +! +! lowering the 'history influence' weight_b (e.g. to 0.1) resulted in +! exceeding the limit for longer-running stuff (compile jobs in +! the .5 to 1.5 sec. range),raising it (e.g. to 0.5) overrepresented +! small jobs' effects. + + */ + +#define LOAD_WEIGHT_A 0.25 +#define LOAD_WEIGHT_B 0.25 + +static int +load_too_high (void) +{ +#if defined(__MSDOS__) || defined(VMS) || defined(_AMIGA) || defined(__riscos__) || defined(__HAIKU__) + return 1; +#else + static double last_sec; + static time_t last_now; + double load, guess; + time_t now; + +#if defined(WINDOWS32) && !defined(CONFIG_NEW_WIN_CHILDREN) + /* sub_proc.c cannot wait for more than MAXIMUM_WAIT_OBJECTS children */ + if (process_used_slots () >= MAXIMUM_WAIT_OBJECTS) + return 1; +#endif + + if (max_load_average < 0) + return 0; + + /* Find the real system load average. */ + make_access (); + if (getloadavg (&load, 1) != 1) + { + static int lossage = -1; + /* Complain only once for the same error. */ + if (lossage == -1 || errno != lossage) + { + if (errno == 0) + /* An errno value of zero means getloadavg is just unsupported. */ + O (error, NILF, + _("cannot enforce load limits on this operating system")); + else + perror_with_name (_("cannot enforce load limit: "), "getloadavg"); + } + lossage = errno; + load = 0; + } + user_access (); + + /* If we're in a new second zero the counter and correct the backlog + value. Only keep the backlog for one extra second; after that it's 0. */ + now = time (NULL); + if (last_now < now) + { + if (last_now == now - 1) + last_sec = LOAD_WEIGHT_B * job_counter; + else + last_sec = 0.0; + + job_counter = 0; + last_now = now; + } + + /* Try to guess what the load would be right now. */ + guess = load + (LOAD_WEIGHT_A * (job_counter + last_sec)); + + DB (DB_JOBS, ("Estimated system load = %f (actual = %f) (max requested = %f)\n", + guess, load, max_load_average)); + + return guess >= max_load_average; +#endif +} + +/* Start jobs that are waiting for the load to be lower. */ + +void +start_waiting_jobs (void) +{ + struct child *job; + + if (waiting_jobs == 0) + return; + + do + { + /* Check for recently deceased descendants. */ + reap_children (0, 0); + + /* Take a job off the waiting list. */ + job = waiting_jobs; + waiting_jobs = job->next; + +#ifdef CONFIG_WITH_EXTENDED_NOTPARALLEL + /* If it's a not-parallel job, we've already counted it once + when it was queued in start_waiting_job, so decrement + before sending it to start_waiting_job again. */ + if (job->file->command_flags & COMMANDS_NOTPARALLEL) + { + DB (DB_KMK, (_("not_parallel %d -> %d (file=%p `%s') [start_waiting_jobs]\n"), + not_parallel, not_parallel - 1, (void *) job->file, job->file->name)); + assert(not_parallel > 0); + --not_parallel; + } +#endif /* CONFIG_WITH_EXTENDED_NOTPARALLEL */ + + /* Try to start that job. We break out of the loop as soon + as start_waiting_job puts one back on the waiting list. */ + } + while (start_waiting_job (job) && waiting_jobs != 0); + + return; +} + +#ifndef WINDOWS32 + +/* EMX: Start a child process. This function returns the new pid. */ +# if defined __EMX__ +int +child_execute_job (struct output *out, int good_stdin, char **argv, char **envp) +{ + int pid; + int fdin = good_stdin ? FD_STDIN : get_bad_stdin (); + int fdout = FD_STDOUT; + int fderr = FD_STDERR; + int save_fdin = -1; + int save_fdout = -1; + int save_fderr = -1; + + /* Divert child output if we want to capture output. */ + if (out && out->syncout) + { + if (out->out >= 0) + fdout = out->out; + if (out->err >= 0) + fderr = out->err; + } + + /* For each FD which needs to be redirected first make a dup of the standard + FD to save and mark it close on exec so our child won't see it. Then + dup2() the standard FD to the redirect FD, and also mark the redirect FD + as close on exec. */ + if (fdin != FD_STDIN) + { + save_fdin = dup (FD_STDIN); + if (save_fdin < 0) + O (fatal, NILF, _("no more file handles: could not duplicate stdin\n")); + CLOSE_ON_EXEC (save_fdin); + + dup2 (fdin, FD_STDIN); + CLOSE_ON_EXEC (fdin); + } + + if (fdout != FD_STDOUT) + { + save_fdout = dup (FD_STDOUT); + if (save_fdout < 0) + O (fatal, NILF, + _("no more file handles: could not duplicate stdout\n")); + CLOSE_ON_EXEC (save_fdout); + + dup2 (fdout, FD_STDOUT); + CLOSE_ON_EXEC (fdout); + } + + if (fderr != FD_STDERR) + { + if (fderr != fdout) + { + save_fderr = dup (FD_STDERR); + if (save_fderr < 0) + O (fatal, NILF, + _("no more file handles: could not duplicate stderr\n")); + CLOSE_ON_EXEC (save_fderr); + } + + dup2 (fderr, FD_STDERR); + CLOSE_ON_EXEC (fderr); + } + + /* Run the command. */ + pid = exec_command (argv, envp); + + /* Restore stdout/stdin/stderr of the parent and close temporary FDs. */ + if (save_fdin >= 0) + { + if (dup2 (save_fdin, FD_STDIN) != FD_STDIN) + O (fatal, NILF, _("Could not restore stdin\n")); + else + close (save_fdin); + } + + if (save_fdout >= 0) + { + if (dup2 (save_fdout, FD_STDOUT) != FD_STDOUT) + O (fatal, NILF, _("Could not restore stdout\n")); + else + close (save_fdout); + } + + if (save_fderr >= 0) + { + if (dup2 (save_fderr, FD_STDERR) != FD_STDERR) + O (fatal, NILF, _("Could not restore stderr\n")); + else + close (save_fderr); + } + + return pid; +} + +#elif !defined (_AMIGA) && !defined (__MSDOS__) && !defined (VMS) + +/* POSIX: + Create a child process executing the command in ARGV. + ENVP is the environment of the new program. Returns the PID or -1. */ +int +child_execute_job (struct output *out, int good_stdin, char **argv, char **envp) +{ + int r; + int pid; + int fdin = good_stdin ? FD_STDIN : get_bad_stdin (); + int fdout = FD_STDOUT; + int fderr = FD_STDERR; + + /* Divert child output if we want to capture it. */ + if (out && out->syncout) + { + if (out->out >= 0) + fdout = out->out; + if (out->err >= 0) + fderr = out->err; + } + + pid = vfork(); + if (pid != 0) + return pid; + + /* We are the child. */ + unblock_sigs (); + +#ifdef SET_STACK_SIZE + /* Reset limits, if necessary. */ + if (stack_limit.rlim_cur) + setrlimit (RLIMIT_STACK, &stack_limit); +#endif + + /* For any redirected FD, dup2() it to the standard FD. + They are all marked close-on-exec already. */ + if (fdin != FD_STDIN) + EINTRLOOP (r, dup2 (fdin, FD_STDIN)); + if (fdout != FD_STDOUT) + EINTRLOOP (r, dup2 (fdout, FD_STDOUT)); + if (fderr != FD_STDERR) + EINTRLOOP (r, dup2 (fderr, FD_STDERR)); + + /* Run the command. */ + exec_command (argv, envp); +} +#endif /* !AMIGA && !__MSDOS__ && !VMS */ +#endif /* !WINDOWS32 */ + +#if !defined(WINDOWS32) || !defined(CONFIG_NEW_WIN_CHILDREN) +#ifndef _AMIGA +/* Replace the current process with one running the command in ARGV, + with environment ENVP. This function does not return. */ + +/* EMX: This function returns the pid of the child process. */ +# ifdef __EMX__ +int +# else +void +# endif +exec_command (char **argv, char **envp) +{ +#ifdef VMS + /* to work around a problem with signals and execve: ignore them */ +#ifdef SIGCHLD + signal (SIGCHLD,SIG_IGN); +#endif + /* Run the program. */ + execve (argv[0], argv, envp); + perror_with_name ("execve: ", argv[0]); + _exit (EXIT_FAILURE); +#else +#ifdef WINDOWS32 +# ifndef CONFIG_NEW_WIN_CHILDREN + HANDLE hPID; + HANDLE hWaitPID; + int exit_code = EXIT_FAILURE; + + /* make sure CreateProcess() has Path it needs */ + sync_Path_environment (); + + /* launch command */ + hPID = process_easy (argv, envp, -1, -1); + + /* make sure launch ok */ + if (hPID == INVALID_HANDLE_VALUE) + { + int i; + fprintf (stderr, _("process_easy() failed to launch process (e=%ld)\n"), + process_last_err (hPID)); + for (i = 0; argv[i]; i++) + fprintf (stderr, "%s ", argv[i]); + fprintf (stderr, _("\nCounted %d args in failed launch\n"), i); + exit (EXIT_FAILURE); + } + + /* wait and reap last child */ + hWaitPID = process_wait_for_any (1, 0); + while (hWaitPID) + { + /* was an error found on this process? */ + int err = process_last_err (hWaitPID); + + /* get exit data */ + exit_code = process_exit_code (hWaitPID); + + if (err) + fprintf (stderr, "make (e=%d, rc=%d): %s", + err, exit_code, map_windows32_error_to_string (err)); + + /* cleanup process */ + process_cleanup (hWaitPID); + + /* expect to find only last pid, warn about other pids reaped */ + if (hWaitPID == hPID) + break; + else + { + char *pidstr = xstrdup (pid2str ((pid_t)hWaitPID)); + + fprintf (stderr, + _("make reaped child pid %s, still waiting for pid %s\n"), + pidstr, pid2str ((pid_t)hPID)); + free (pidstr); + } + } + + /* return child's exit code as our exit code */ + exit (exit_code); +# else /* CONFIG_NEW_WIN_CHILDREN */ + +# endif /* CONFIG_NEW_WIN_CHILDREN */ +#else /* !WINDOWS32 */ + +# ifdef __EMX__ + int pid; +# endif + + /* Be the user, permanently. */ + child_access (); + +# ifdef __EMX__ + /* Run the program. */ + pid = spawnvpe (P_NOWAIT, argv[0], argv, envp); + if (pid >= 0) + return pid; + + /* the file might have a strange shell extension */ + if (errno == ENOENT) + errno = ENOEXEC; + +# else + /* Run the program. */ + environ = envp; + execvp (argv[0], argv); + +# endif /* !__EMX__ */ + + switch (errno) + { + case ENOENT: + /* We are in the child: don't use the output buffer. + It's not right to run fprintf() here! */ + if (makelevel == 0) + fprintf (stderr, _("%s: %s: Command not found\n"), program, argv[0]); + else + fprintf (stderr, _("%s[%u]: %s: Command not found\n"), + program, makelevel, argv[0]); + break; + case ENOEXEC: + { + /* The file is not executable. Try it as a shell script. */ + const char *shell; + char **new_argv; + int argc; + int i=1; + +# ifdef __EMX__ + /* Do not use $SHELL from the environment */ + struct variable *p = lookup_variable ("SHELL", 5); + if (p) + shell = p->value; + else + shell = 0; +# else + shell = getenv ("SHELL"); +# endif + if (shell == 0) + shell = default_shell; + + argc = 1; + while (argv[argc] != 0) + ++argc; + +# ifdef __EMX__ + if (!unixy_shell) + ++argc; +# endif + + new_argv = alloca ((1 + argc + 1) * sizeof (char *)); + new_argv[0] = (char *)shell; + +# ifdef __EMX__ + if (!unixy_shell) + { + new_argv[1] = "/c"; + ++i; + --argc; + } +# endif + + new_argv[i] = argv[0]; + while (argc > 0) + { + new_argv[i + argc] = argv[argc]; + --argc; + } + +# ifdef __EMX__ + pid = spawnvpe (P_NOWAIT, shell, new_argv, envp); + if (pid >= 0) + break; +# else + execvp (shell, new_argv); +# endif + if (errno == ENOENT) + OS (error, NILF, _("%s: Shell program not found"), shell); + else + perror_with_name ("execvp: ", shell); + break; + } + +# ifdef __EMX__ + case EINVAL: + /* this nasty error was driving me nuts :-( */ + O (error, NILF, _("spawnvpe: environment space might be exhausted")); + /* FALLTHROUGH */ +# endif + + default: + perror_with_name ("execvp: ", argv[0]); + break; + } + +# ifdef __EMX__ + return pid; +# else + _exit (127); +# endif +#endif /* !WINDOWS32 */ +#endif /* !VMS */ +} +#else /* On Amiga */ +void +exec_command (char **argv) +{ + MyExecute (argv); +} + +void clean_tmp (void) +{ + DeleteFile (amiga_bname); +} + +#endif /* On Amiga */ +#endif /* !defined(WINDOWS32) || !defined(CONFIG_NEW_WIN_CHILDREN) */ + +#ifndef VMS +/* Figure out the argument list necessary to run LINE as a command. Try to + avoid using a shell. This routine handles only ' quoting, and " quoting + when no backslash, $ or ' characters are seen in the quotes. Starting + quotes may be escaped with a backslash. If any of the characters in + sh_chars is seen, or any of the builtin commands listed in sh_cmds + is the first word of a line, the shell is used. + + If RESTP is not NULL, *RESTP is set to point to the first newline in LINE. + If *RESTP is NULL, newlines will be ignored. + + SHELL is the shell to use, or nil to use the default shell. + IFS is the value of $IFS, or nil (meaning the default). + + FLAGS is the value of lines_flags for this command line. It is + used in the WINDOWS32 port to check whether + or $(MAKE) were found + in this command line, in which case the effect of just_print_flag + is overridden. */ + +static char ** +construct_command_argv_internal (char *line, char **restp, const char *shell, + const char *shellflags, const char *ifs, + int flags, char **batch_filename UNUSED) +{ +#ifdef __MSDOS__ + /* MSDOS supports both the stock DOS shell and ports of Unixy shells. + We call 'system' for anything that requires ''slow'' processing, + because DOS shells are too dumb. When $SHELL points to a real + (unix-style) shell, 'system' just calls it to do everything. When + $SHELL points to a DOS shell, 'system' does most of the work + internally, calling the shell only for its internal commands. + However, it looks on the $PATH first, so you can e.g. have an + external command named 'mkdir'. + + Since we call 'system', certain characters and commands below are + actually not specific to COMMAND.COM, but to the DJGPP implementation + of 'system'. In particular: + + The shell wildcard characters are in DOS_CHARS because they will + not be expanded if we call the child via 'spawnXX'. + + The ';' is in DOS_CHARS, because our 'system' knows how to run + multiple commands on a single line. + + DOS_CHARS also include characters special to 4DOS/NDOS, so we + won't have to tell one from another and have one more set of + commands and special characters. */ + static const char *sh_chars_dos = "*?[];|<>%^&()"; + static const char *sh_cmds_dos[] = + { "break", "call", "cd", "chcp", "chdir", "cls", "copy", "ctty", "date", + "del", "dir", "echo", "erase", "exit", "for", "goto", "if", "md", + "mkdir", "path", "pause", "prompt", "rd", "rmdir", "rem", "ren", + "rename", "set", "shift", "time", "type", "ver", "verify", "vol", ":", + 0 }; + + static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^"; + static const char *sh_cmds_sh[] = + { "cd", "echo", "eval", "exec", "exit", "login", "logout", "set", "umask", + "wait", "while", "for", "case", "if", ":", ".", "break", "continue", + "export", "read", "readonly", "shift", "times", "trap", "switch", + "unset", "ulimit", 0 }; + + const char *sh_chars; + const char **sh_cmds; + +#elif defined (__EMX__) + static const char *sh_chars_dos = "*?[];|<>%^&()"; + static const char *sh_cmds_dos[] = + { "break", "call", "cd", "chcp", "chdir", "cls", "copy", "ctty", "date", + "del", "dir", "echo", "erase", "exit", "for", "goto", "if", "md", + "mkdir", "path", "pause", "prompt", "rd", "rmdir", "rem", "ren", + "rename", "set", "shift", "time", "type", "ver", "verify", "vol", ":", + 0 }; + + static const char *sh_chars_os2 = "*?[];|<>%^()\"'&"; + static const char *sh_cmds_os2[] = + { "call", "cd", "chcp", "chdir", "cls", "copy", "date", "del", "detach", + "dir", "echo", "endlocal", "erase", "exit", "for", "goto", "if", "keys", + "md", "mkdir", "move", "path", "pause", "prompt", "rd", "rem", "ren", + "rename", "rmdir", "set", "setlocal", "shift", "start", "time", "type", + "ver", "verify", "vol", ":", 0 }; + + static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^~'"; + static const char *sh_cmds_sh[] = + { "echo", "cd", "eval", "exec", "exit", "login", "logout", "set", "umask", + "wait", "while", "for", "case", "if", ":", ".", "break", "continue", + "export", "read", "readonly", "shift", "times", "trap", "switch", + "unset", 0 }; + + const char *sh_chars; + const char **sh_cmds; + +#elif defined (_AMIGA) + static const char *sh_chars = "#;\"|<>()?*$`"; + static const char *sh_cmds[] = + { "cd", "eval", "if", "delete", "echo", "copy", "rename", "set", "setenv", + "date", "makedir", "skip", "else", "endif", "path", "prompt", "unset", + "unsetenv", "version", 0 }; + +#elif defined (WINDOWS32) + /* We used to have a double quote (") in sh_chars_dos[] below, but + that caused any command line with quoted file names be run + through a temporary batch file, which introduces command-line + limit of 4K charcaters imposed by cmd.exe. Since CreateProcess + can handle quoted file names just fine, removing the quote lifts + the limit from a very frequent use case, because using quoted + file names is commonplace on MS-Windows. */ + static const char *sh_chars_dos = "|&<>"; + static const char *sh_cmds_dos[] = + { "assoc", "break", "call", "cd", "chcp", "chdir", "cls", "color", "copy", + "ctty", "date", "del", "dir", "echo", "echo.", "endlocal", "erase", + "exit", "for", "ftype", "goto", "if", "if", "md", "mkdir", "move", + "path", "pause", "prompt", "rd", "rem", "ren", "rename", "rmdir", + "set", "setlocal", "shift", "time", "title", "type", "ver", "verify", + "vol", ":", 0 }; + + static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^"; + static const char *sh_cmds_sh[] = + { "cd", "eval", "exec", "exit", "login", "logout", "set", "umask", "wait", + "while", "for", "case", "if", ":", ".", "break", "continue", "export", + "read", "readonly", "shift", "times", "trap", "switch", "test", +#ifdef BATCH_MODE_ONLY_SHELL + "echo", +#endif + 0 }; + + const char *sh_chars; + char const * const * sh_cmds; /* kmk: +_sh +const*2 */ +#elif defined(__riscos__) + static const char *sh_chars = ""; + static const char *sh_cmds[] = { 0 }; +#else /* must be UNIX-ish */ + static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^~!"; /* kmk: +_sh */ + static const char *sh_cmds_sh[] = /* kmk: +_sh */ + { ".", ":", "break", "case", "cd", "continue", "eval", "exec", "exit", + "export", "for", "if", "login", "logout", "read", "readonly", "set", + "shift", "switch", "test", "times", "trap", "ulimit", "umask", "unset", + "wait", "while", 0 }; + +# if 0 /*def HAVE_DOS_PATHS - kmk */ + /* This is required if the MSYS/Cygwin ports (which do not define + WINDOWS32) are compiled with HAVE_DOS_PATHS defined, which uses + sh_chars_sh directly (see below). The value must be identical + to that of sh_chars immediately above. */ + static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^~!"; +# endif /* HAVE_DOS_PATHS */ + char const * sh_chars = sh_chars_sh; /* kmk: +_sh +const */ + char const * const * sh_cmds = sh_cmds_sh; /* kmk: +_sh +const*2 */ +#endif +#ifdef KMK + static const char sh_chars_kash[] = "#;*?[]&|<>(){}$`^~!"; /* note: no \" - good idea? */ + static const char * const sh_cmds_kash[] = { + ".", ":", "break", "case", "cd", "continue", "echo", "eval", "exec", "exit", + "export", "for", "if", "login", "logout", "read", "readonly", "set", + "shift", "switch", "test", "times", "trap", "umask", "wait", "while", 0 /* +echo, -ulimit, -unset */ + }; + int is_kmk_shell = 0; +#endif + int i; + char *p; +#ifndef NDEBUG + char *end; +#endif + char *ap; + const char *cap; + const char *cp; + int instring, word_has_equals, seen_nonequals, last_argument_was_empty; + char **new_argv = 0; + char *argstr = 0; +#ifdef WINDOWS32 + int slow_flag = 0; + + if (!unixy_shell) + { + sh_cmds = sh_cmds_dos; + sh_chars = sh_chars_dos; + } + else + { + sh_cmds = sh_cmds_sh; + sh_chars = sh_chars_sh; + } +#endif /* WINDOWS32 */ + + if (restp != NULL) + *restp = NULL; + + /* Make sure not to bother processing an empty line but stop at newline. */ + while (ISBLANK (*line)) + ++line; + if (*line == '\0') + return 0; + + if (shellflags == 0) + shellflags = posix_pedantic ? "-ec" : "-c"; + + /* See if it is safe to parse commands internally. */ +#ifdef KMK /* kmk_ash and kmk_kash are both fine, kmk_ash is the default btw. */ + if (shell == 0) + { + is_kmk_shell = 1; + shell = (char *)get_default_kbuild_shell (); + } + else if (!strcmp (shell, get_default_kbuild_shell())) + is_kmk_shell = 1; + else + { + const char *psz = strstr (shell, "/kmk_ash"); + if (psz) + psz += sizeof ("/kmk_ash") - 1; + else + { + psz = strstr (shell, "/kmk_kash"); + if (psz) + psz += sizeof ("/kmk_kash") - 1; + } +# if defined (__OS2__) || defined (_WIN32) || defined (WINDOWS32) + is_kmk_shell = psz && (*psz == '\0' || !stricmp (psz, ".exe")); +# else + is_kmk_shell = psz && *psz == '\0'; +# endif + } + if (is_kmk_shell) + { + sh_chars = sh_chars_kash; + sh_cmds = sh_cmds_kash; + } +#else /* !KMK */ + if (shell == 0) + shell = default_shell; +#endif /* !KMK */ +#ifdef WINDOWS32 + else if (strcmp (shell, default_shell)) + { + char *s1 = _fullpath (NULL, shell, 0); + char *s2 = _fullpath (NULL, default_shell, 0); + + slow_flag = strcmp ((s1 ? s1 : ""), (s2 ? s2 : "")); + + free (s1); + free (s2); + } + if (slow_flag) + goto slow; +#else /* not WINDOWS32 */ +#if defined (__MSDOS__) || defined (__EMX__) + else if (strcasecmp (shell, default_shell)) + { + extern int _is_unixy_shell (const char *_path); + + DB (DB_BASIC, (_("$SHELL changed (was '%s', now '%s')\n"), + default_shell, shell)); + unixy_shell = _is_unixy_shell (shell); + /* we must allocate a copy of shell: construct_command_argv() will free + * shell after this function returns. */ + default_shell = xstrdup (shell); + } +# ifdef KMK + if (is_kmk_shell) + { /* done above already */ } + else +# endif + if (unixy_shell) + { + sh_chars = sh_chars_sh; + sh_cmds = sh_cmds_sh; + } + else + { + sh_chars = sh_chars_dos; + sh_cmds = sh_cmds_dos; +# ifdef __EMX__ + if (_osmode == OS2_MODE) + { + sh_chars = sh_chars_os2; + sh_cmds = sh_cmds_os2; + } +# endif + } +#else /* !__MSDOS__ */ + else if (strcmp (shell, default_shell)) + goto slow; +#endif /* !__MSDOS__ && !__EMX__ */ +#endif /* not WINDOWS32 */ + + if (ifs) + for (cap = ifs; *cap != '\0'; ++cap) + if (*cap != ' ' && *cap != '\t' && *cap != '\n') + goto slow; + + if (shellflags) + if (shellflags[0] != '-' + || ((shellflags[1] != 'c' || shellflags[2] != '\0') + && (shellflags[1] != 'e' || shellflags[2] != 'c' || shellflags[3] != '\0'))) + goto slow; + + i = strlen (line) + 1; + + /* More than 1 arg per character is impossible. */ + new_argv = xmalloc (i * sizeof (char *)); + + /* All the args can fit in a buffer as big as LINE is. */ + ap = new_argv[0] = argstr = xmalloc (i); +#ifndef NDEBUG + end = ap + i; +#endif + + /* I is how many complete arguments have been found. */ + i = 0; + instring = word_has_equals = seen_nonequals = last_argument_was_empty = 0; + for (p = line; *p != '\0'; ++p) + { + assert (ap <= end); + + if (instring) + { + /* Inside a string, just copy any char except a closing quote + or a backslash-newline combination. */ + if (*p == instring) + { + instring = 0; + if (ap == new_argv[0] || *(ap-1) == '\0') + last_argument_was_empty = 1; + } + else if (*p == '\\' && p[1] == '\n') + { + /* Backslash-newline is handled differently depending on what + kind of string we're in: inside single-quoted strings you + keep them; in double-quoted strings they disappear. For + DOS/Windows/OS2, if we don't have a POSIX shell, we keep the + pre-POSIX behavior of removing the backslash-newline. */ + if (instring == '"' +#if defined (__MSDOS__) || defined (__EMX__) || defined (WINDOWS32) + || !unixy_shell +#endif + ) + ++p; + else + { + *(ap++) = *(p++); + *(ap++) = *p; + } + } + else if (*p == '\n' && restp != NULL) + { + /* End of the command line. */ + *restp = p; + goto end_of_line; + } + /* Backslash, $, and ` are special inside double quotes. + If we see any of those, punt. + But on MSDOS, if we use COMMAND.COM, double and single + quotes have the same effect. */ + else if (instring == '"' && strchr ("\\$`", *p) != 0 && unixy_shell) + goto slow; +#ifdef WINDOWS32 + /* Quoted wildcard characters must be passed quoted to the + command, so give up the fast route. */ + else if (instring == '"' && strchr ("*?", *p) != 0 && !unixy_shell) + goto slow; + else if (instring == '"' && strncmp (p, "\\\"", 2) == 0) + *ap++ = *++p; +#endif + else + *ap++ = *p; + } + else if (strchr (sh_chars, *p) != 0) +#ifdef KMK + { + /* Tilde is only special if at the start of a path spec, + i.e. don't get excited when we by 8.3 files on windows. */ + if ( *p == '~' + && p > line + && !ISSPACE (p[-1]) + && p[-1] != '=' + && p[-1] != ':' + && p[-1] != '"' + && p[-1] != '\'') + *ap++ = *p; + else + /* Not inside a string, but it's a special char. */ + goto slow; + } +#else /* !KMK */ + /* Not inside a string, but it's a special char. */ + goto slow; +#endif /* !KMK */ + else if (one_shell && *p == '\n') + /* In .ONESHELL mode \n is a separator like ; or && */ + goto slow; +#ifdef __MSDOS__ + else if (*p == '.' && p[1] == '.' && p[2] == '.' && p[3] != '.') + /* '...' is a wildcard in DJGPP. */ + goto slow; +#endif + else + /* Not a special char. */ + switch (*p) + { + case '=': + /* Equals is a special character in leading words before the + first word with no equals sign in it. This is not the case + with sh -k, but we never get here when using nonstandard + shell flags. */ + if (! seen_nonequals && unixy_shell) + goto slow; + word_has_equals = 1; + *ap++ = '='; + break; + + case '\\': + /* Backslash-newline has special case handling, ref POSIX. + We're in the fastpath, so emulate what the shell would do. */ + if (p[1] == '\n') + { + /* Throw out the backslash and newline. */ + ++p; + + /* At the beginning of the argument, skip any whitespace other + than newline before the start of the next word. */ + if (ap == new_argv[i]) + while (ISBLANK (p[1])) + ++p; + } +#ifdef WINDOWS32 + /* Backslash before whitespace is not special if our shell + is not Unixy. */ + else if (ISSPACE (p[1]) && !unixy_shell) + { + *ap++ = *p; + break; + } +#endif + else if (p[1] != '\0') + { +#ifdef HAVE_DOS_PATHS + /* Only remove backslashes before characters special to Unixy + shells. All other backslashes are copied verbatim, since + they are probably DOS-style directory separators. This + still leaves a small window for problems, but at least it + should work for the vast majority of naive users. */ + +#ifdef __MSDOS__ + /* A dot is only special as part of the "..." + wildcard. */ + if (strneq (p + 1, ".\\.\\.", 5)) + { + *ap++ = '.'; + *ap++ = '.'; + p += 4; + } + else +#endif + if (p[1] != '\\' && p[1] != '\'' + && !ISSPACE (p[1]) +# ifdef KMK + && strchr (sh_chars, p[1]) == 0 + && (p[1] != '"' || !unixy_shell)) +# else + && strchr (sh_chars_sh, p[1]) == 0) +# endif + /* back up one notch, to copy the backslash */ + --p; +#endif /* HAVE_DOS_PATHS */ + + /* Copy and skip the following char. */ + *ap++ = *++p; + } + break; + + case '\'': + case '"': + instring = *p; + break; + + case '\n': + if (restp != NULL) + { + /* End of the command line. */ + *restp = p; + goto end_of_line; + } + else + /* Newlines are not special. */ + *ap++ = '\n'; + break; + + case ' ': + case '\t': + /* We have the end of an argument. + Terminate the text of the argument. */ + *ap++ = '\0'; + new_argv[++i] = ap; + last_argument_was_empty = 0; + + /* Update SEEN_NONEQUALS, which tells us if every word + heretofore has contained an '='. */ + seen_nonequals |= ! word_has_equals; + if (word_has_equals && ! seen_nonequals) + /* An '=' in a word before the first + word without one is magical. */ + goto slow; + word_has_equals = 0; /* Prepare for the next word. */ + + /* If this argument is the command name, + see if it is a built-in shell command. + If so, have the shell handle it. */ + if (i == 1) + { + register int j; + for (j = 0; sh_cmds[j] != 0; ++j) + { + if (streq (sh_cmds[j], new_argv[0])) + goto slow; +#if defined(__EMX__) || defined(WINDOWS32) + /* Non-Unix shells are case insensitive. */ + if (!unixy_shell + && strcasecmp (sh_cmds[j], new_argv[0]) == 0) + goto slow; +#endif + } + } + + /* Skip whitespace chars, but not newlines. */ + while (ISBLANK (p[1])) + ++p; + break; + + default: + *ap++ = *p; + break; + } + } + end_of_line: + + if (instring) + /* Let the shell deal with an unterminated quote. */ + goto slow; + + /* Terminate the last argument and the argument list. */ + + *ap = '\0'; + if (new_argv[i][0] != '\0' || last_argument_was_empty) + ++i; + new_argv[i] = 0; + + if (i == 1) + { + register int j; + for (j = 0; sh_cmds[j] != 0; ++j) + if (streq (sh_cmds[j], new_argv[0])) + goto slow; + } + + if (new_argv[0] == 0) + { + /* Line was empty. */ + free (argstr); + free (new_argv); + return 0; + } + + return new_argv; + + slow:; + /* We must use the shell. */ + + if (new_argv != 0) + { + /* Free the old argument list we were working on. */ + free (argstr); + free (new_argv); + } + +#ifdef __MSDOS__ + execute_by_shell = 1; /* actually, call 'system' if shell isn't unixy */ +#endif + +#ifdef _AMIGA + { + char *ptr; + char *buffer; + char *dptr; + + buffer = xmalloc (strlen (line)+1); + + ptr = line; + for (dptr=buffer; *ptr; ) + { + if (*ptr == '\\' && ptr[1] == '\n') + ptr += 2; + else if (*ptr == '@') /* Kludge: multiline commands */ + { + ptr += 2; + *dptr++ = '\n'; + } + else + *dptr++ = *ptr++; + } + *dptr = 0; + + new_argv = xmalloc (2 * sizeof (char *)); + new_argv[0] = buffer; + new_argv[1] = 0; + } +#else /* Not Amiga */ +#ifdef WINDOWS32 + /* + * Not eating this whitespace caused things like + * + * sh -c "\n" + * + * which gave the shell fits. I think we have to eat + * whitespace here, but this code should be considered + * suspicious if things start failing.... + */ + + /* Make sure not to bother processing an empty line. */ + NEXT_TOKEN (line); + if (*line == '\0') + return 0; +#endif /* WINDOWS32 */ + + { + /* SHELL may be a multi-word command. Construct a command line + "$(SHELL) $(.SHELLFLAGS) LINE", with all special chars in LINE escaped. + Then recurse, expanding this command line to get the final + argument list. */ + + char *new_line; + unsigned int shell_len = strlen (shell); + unsigned int line_len = strlen (line); + unsigned int sflags_len = shellflags ? strlen (shellflags) : 0; +#ifdef WINDOWS32 + char *command_ptr = NULL; /* used for batch_mode_shell mode */ +#endif + +# ifdef __EMX__ /* is this necessary? */ + if (!unixy_shell && shellflags) + ((char *)shellflags)[0] = '/'; /* "/c" */ +# endif + + /* In .ONESHELL mode we are allowed to throw the entire current + recipe string at a single shell and trust that the user + has configured the shell and shell flags, and formatted + the string, appropriately. */ + if (one_shell) + { + /* If the shell is Bourne compatible, we must remove and ignore + interior special chars [@+-] because they're meaningless to + the shell itself. If, however, we're in .ONESHELL mode and + have changed SHELL to something non-standard, we should + leave those alone because they could be part of the + script. In this case we must also leave in place + any leading [@+-] for the same reason. */ + + /* Remove and ignore interior prefix chars [@+-] because they're + meaningless given a single shell. */ +#if defined __MSDOS__ || defined (__EMX__) + if (unixy_shell) /* the test is complicated and we already did it */ +#else + if (is_bourne_compatible_shell (shell) +#ifdef WINDOWS32 + /* If we didn't find any sh.exe, don't behave is if we did! */ + && !no_default_sh_exe +#endif + ) +#endif + { + const char *f = line; + char *t = line; + + /* Copy the recipe, removing and ignoring interior prefix chars + [@+-]: they're meaningless in .ONESHELL mode. */ + while (f[0] != '\0') + { + int esc = 0; + + /* This is the start of a new recipe line. Skip whitespace + and prefix characters but not newlines. */ +#ifndef CONFIG_WITH_COMMANDS_FUNC + while (ISBLANK (*f) || *f == '-' || *f == '@' || *f == '+') +#else + char ch; + while (ISBLANK ((ch = *f)) || ch == '-' || ch == '@' || ch == '+' || ch == '%') +#endif + ++f; + + /* Copy until we get to the next logical recipe line. */ + while (*f != '\0') + { + *(t++) = *(f++); + if (f[-1] == '\\') + esc = !esc; + else + { + /* On unescaped newline, we're done with this line. */ + if (f[-1] == '\n' && ! esc) + break; + + /* Something else: reset the escape sequence. */ + esc = 0; + } + } + } + *t = '\0'; + } +#ifdef WINDOWS32 + else /* non-Posix shell (cmd.exe etc.) */ + { + const char *f = line; + char *t = line; + char *tstart = t; + int temp_fd; + FILE* batch = NULL; + int id = GetCurrentProcessId (); + PATH_VAR(fbuf); + + /* Generate a file name for the temporary batch file. */ + sprintf (fbuf, "make%d", id); + *batch_filename = create_batch_file (fbuf, 0, &temp_fd); + DB (DB_JOBS, (_("Creating temporary batch file %s\n"), + *batch_filename)); + + /* Create a FILE object for the batch file, and write to it the + commands to be executed. Put the batch file in TEXT mode. */ + _setmode (temp_fd, _O_TEXT); + batch = _fdopen (temp_fd, "wt"); + fputs ("@echo off\n", batch); + DB (DB_JOBS, (_("Batch file contents:\n\t@echo off\n"))); + + /* Copy the recipe, removing and ignoring interior prefix chars + [@+-]: they're meaningless in .ONESHELL mode. */ + while (*f != '\0') + { + /* This is the start of a new recipe line. Skip whitespace + and prefix characters but not newlines. */ +#ifndef CONFIG_WITH_COMMANDS_FUNC + while (ISBLANK (*f) || *f == '-' || *f == '@' || *f == '+') +#else + char ch; + while (ISBLANK ((ch = *f)) || ch == '-' || ch == '@' || ch == '+' || ch == '%') +#endif + ++f; + + /* Copy until we get to the next logical recipe line. */ + while (*f != '\0') + { + /* Remove the escaped newlines in the command, and the + blanks that follow them. Windows shells cannot handle + escaped newlines. */ + if (*f == '\\' && f[1] == '\n') + { + f += 2; + while (ISBLANK (*f)) + ++f; + } + *(t++) = *(f++); + /* On an unescaped newline, we're done with this + line. */ + if (f[-1] == '\n') + break; + } + /* Write another line into the batch file. */ + if (t > tstart) + { + char c = *t; + *t = '\0'; + fputs (tstart, batch); + DB (DB_JOBS, ("\t%s", tstart)); + tstart = t; + *t = c; + } + } + DB (DB_JOBS, ("\n")); + fclose (batch); + + /* Create an argv list for the shell command line that + will run the batch file. */ + new_argv = xmalloc (2 * sizeof (char *)); + new_argv[0] = xstrdup (*batch_filename); + new_argv[1] = NULL; + return new_argv; + } +#endif /* WINDOWS32 */ + /* Create an argv list for the shell command line. */ + { + int n = 0; + + new_argv = xmalloc ((4 + sflags_len/2) * sizeof (char *)); + new_argv[n++] = xstrdup (shell); + + /* Chop up the shellflags (if any) and assign them. */ + if (! shellflags) + new_argv[n++] = xstrdup (""); + else + { + const char *s = shellflags; + char *t; + unsigned int len; + while ((t = find_next_token (&s, &len)) != 0) + new_argv[n++] = xstrndup (t, len); + } + + /* Set the command to invoke. */ + new_argv[n++] = line; + new_argv[n++] = NULL; + } + return new_argv; + } + + new_line = xmalloc ((shell_len*2) + 1 + sflags_len + 1 + + (line_len*2) + 1); + ap = new_line; + /* Copy SHELL, escaping any characters special to the shell. If + we don't escape them, construct_command_argv_internal will + recursively call itself ad nauseam, or until stack overflow, + whichever happens first. */ + for (cp = shell; *cp != '\0'; ++cp) + { + if (strchr (sh_chars, *cp) != 0) + *(ap++) = '\\'; + *(ap++) = *cp; + } + *(ap++) = ' '; + if (shellflags) + memcpy (ap, shellflags, sflags_len); + ap += sflags_len; + *(ap++) = ' '; +#ifdef WINDOWS32 + command_ptr = ap; +#endif + for (p = line; *p != '\0'; ++p) + { + if (restp != NULL && *p == '\n') + { + *restp = p; + break; + } + else if (*p == '\\' && p[1] == '\n') + { + /* POSIX says we keep the backslash-newline. If we don't have a + POSIX shell on DOS/Windows/OS2, mimic the pre-POSIX behavior + and remove the backslash/newline. */ +#if defined (__MSDOS__) || defined (__EMX__) || defined (WINDOWS32) +# define PRESERVE_BSNL unixy_shell +#else +# define PRESERVE_BSNL 1 +#endif + if (PRESERVE_BSNL) + { + *(ap++) = '\\'; + /* Only non-batch execution needs another backslash, + because it will be passed through a recursive + invocation of this function. */ + if (!batch_mode_shell) + *(ap++) = '\\'; + *(ap++) = '\n'; + } + ++p; + continue; + } + + /* DOS shells don't know about backslash-escaping. */ + if (unixy_shell && !batch_mode_shell && + (*p == '\\' || *p == '\'' || *p == '"' + || ISSPACE (*p) + || strchr (sh_chars, *p) != 0)) + *ap++ = '\\'; +#ifdef __MSDOS__ + else if (unixy_shell && strneq (p, "...", 3)) + { + /* The case of '...' wildcard again. */ + strcpy (ap, "\\.\\.\\"); + ap += 5; + p += 2; + } +#endif + *ap++ = *p; + } + if (ap == new_line + shell_len + sflags_len + 2) + { + /* Line was empty. */ + free (new_line); + return 0; + } + *ap = '\0'; + +#ifdef WINDOWS32 + /* Some shells do not work well when invoked as 'sh -c xxx' to run a + command line (e.g. Cygnus GNUWIN32 sh.exe on WIN32 systems). In these + cases, run commands via a script file. */ + if (just_print_flag && !(flags & COMMANDS_RECURSE)) + { + /* Need to allocate new_argv, although it's unused, because + start_job_command will want to free it and its 0'th element. */ + new_argv = xmalloc (2 * sizeof (char *)); + new_argv[0] = xstrdup (""); + new_argv[1] = NULL; + } + else if ((no_default_sh_exe || batch_mode_shell) && batch_filename) + { + int temp_fd; + FILE* batch = NULL; + int id = GetCurrentProcessId (); + PATH_VAR (fbuf); + + /* create a file name */ + sprintf (fbuf, "make%d", id); + *batch_filename = create_batch_file (fbuf, unixy_shell, &temp_fd); + + DB (DB_JOBS, (_("Creating temporary batch file %s\n"), + *batch_filename)); + + /* Create a FILE object for the batch file, and write to it the + commands to be executed. Put the batch file in TEXT mode. */ + _setmode (temp_fd, _O_TEXT); + batch = _fdopen (temp_fd, "wt"); + if (!unixy_shell) + fputs ("@echo off\n", batch); + fputs (command_ptr, batch); + fputc ('\n', batch); + fclose (batch); + DB (DB_JOBS, (_("Batch file contents:%s\n\t%s\n"), + !unixy_shell ? "\n\t@echo off" : "", command_ptr)); + + /* create argv */ + new_argv = xmalloc (3 * sizeof (char *)); + if (unixy_shell) + { + new_argv[0] = xstrdup (shell); + new_argv[1] = *batch_filename; /* only argv[0] gets freed later */ + } + else + { + new_argv[0] = xstrdup (*batch_filename); + new_argv[1] = NULL; + } + new_argv[2] = NULL; + } + else +#endif /* WINDOWS32 */ + + if (unixy_shell) + new_argv = construct_command_argv_internal (new_line, 0, 0, 0, 0, + flags, 0); + +#ifdef __EMX__ + else if (!unixy_shell) + { + /* new_line is local, must not be freed therefore + We use line here instead of new_line because we run the shell + manually. */ + size_t line_len = strlen (line); + char *p = new_line; + char *q = new_line; + memcpy (new_line, line, line_len + 1); + /* Replace all backslash-newline combination and also following tabs. + Important: stop at the first '\n' because that's what the loop above + did. The next line starting at restp[0] will be executed during the + next call of this function. */ + while (*q != '\0' && *q != '\n') + { + if (q[0] == '\\' && q[1] == '\n') + q += 2; /* remove '\\' and '\n' */ + else + *p++ = *q++; + } + *p = '\0'; + +# ifndef NO_CMD_DEFAULT + if (strnicmp (new_line, "echo", 4) == 0 + && (new_line[4] == ' ' || new_line[4] == '\t')) + { + /* the builtin echo command: handle it separately */ + size_t echo_len = line_len - 5; + char *echo_line = new_line + 5; + + /* special case: echo 'x="y"' + cmd works this way: a string is printed as is, i.e., no quotes + are removed. But autoconf uses a command like echo 'x="y"' to + determine whether make works. autoconf expects the output x="y" + so we will do exactly that. + Note: if we do not allow cmd to be the default shell + we do not need this kind of voodoo */ + if (echo_line[0] == '\'' + && echo_line[echo_len - 1] == '\'' + && strncmp (echo_line + 1, "ac_maketemp=", + strlen ("ac_maketemp=")) == 0) + { + /* remove the enclosing quotes */ + memmove (echo_line, echo_line + 1, echo_len - 2); + echo_line[echo_len - 2] = '\0'; + } + } +# endif + + { + /* Let the shell decide what to do. Put the command line into the + 2nd command line argument and hope for the best ;-) */ + size_t sh_len = strlen (shell); + + /* exactly 3 arguments + NULL */ + new_argv = xmalloc (4 * sizeof (char *)); + /* Exactly strlen(shell) + strlen("/c") + strlen(line) + 3 times + the trailing '\0' */ + new_argv[0] = xmalloc (sh_len + line_len + 5); + memcpy (new_argv[0], shell, sh_len + 1); + new_argv[1] = new_argv[0] + sh_len + 1; + memcpy (new_argv[1], "/c", 3); + new_argv[2] = new_argv[1] + 3; + memcpy (new_argv[2], new_line, line_len + 1); + new_argv[3] = NULL; + } + } +#elif defined(__MSDOS__) + else + { + /* With MSDOS shells, we must construct the command line here + instead of recursively calling ourselves, because we + cannot backslash-escape the special characters (see above). */ + new_argv = xmalloc (sizeof (char *)); + line_len = strlen (new_line) - shell_len - sflags_len - 2; + new_argv[0] = xmalloc (line_len + 1); + strncpy (new_argv[0], + new_line + shell_len + sflags_len + 2, line_len); + new_argv[0][line_len] = '\0'; + } +#else + else + fatal (NILF, CSTRLEN (__FILE__) + INTSTR_LENGTH, + _("%s (line %d) Bad shell context (!unixy && !batch_mode_shell)\n"), + __FILE__, __LINE__); +#endif + + free (new_line); + } +#endif /* ! AMIGA */ + + return new_argv; +} +#endif /* !VMS */ + +/* Figure out the argument list necessary to run LINE as a command. Try to + avoid using a shell. This routine handles only ' quoting, and " quoting + when no backslash, $ or ' characters are seen in the quotes. Starting + quotes may be escaped with a backslash. If any of the characters in + sh_chars is seen, or any of the builtin commands listed in sh_cmds + is the first word of a line, the shell is used. + + If RESTP is not NULL, *RESTP is set to point to the first newline in LINE. + If *RESTP is NULL, newlines will be ignored. + + FILE is the target whose commands these are. It is used for + variable expansion for $(SHELL) and $(IFS). */ + +char ** +construct_command_argv (char *line, char **restp, struct file *file, + int cmd_flags, char **batch_filename) +{ + char *shell, *ifs, *shellflags; + char **argv; + +#ifdef VMS + char *cptr; + int argc; + + argc = 0; + cptr = line; + for (;;) + { + while ((*cptr != 0) && (ISSPACE (*cptr))) + cptr++; + if (*cptr == 0) + break; + while ((*cptr != 0) && (!ISSPACE (*cptr))) + cptr++; + argc++; + } + + argv = xmalloc (argc * sizeof (char *)); + if (argv == 0) + abort (); + + cptr = line; + argc = 0; + for (;;) + { + while ((*cptr != 0) && (ISSPACE (*cptr))) + cptr++; + if (*cptr == 0) + break; + DB (DB_JOBS, ("argv[%d] = [%s]\n", argc, cptr)); + argv[argc++] = cptr; + while ((*cptr != 0) && (!ISSPACE (*cptr))) + cptr++; + if (*cptr != 0) + *cptr++ = 0; + } +#else + { + /* Turn off --warn-undefined-variables while we expand SHELL and IFS. */ + int save = warn_undefined_variables_flag; + warn_undefined_variables_flag = 0; + + shell = allocated_variable_expand_for_file ("$(SHELL)", file); +#ifdef WINDOWS32 + /* + * Convert to forward slashes so that construct_command_argv_internal() + * is not confused. + */ + if (shell) + { +# if 1 /* bird */ + unix_slashes (shell); +# else + char *p = w32ify (shell, 0); + strcpy (shell, p); +# endif + } +#endif +#ifdef __EMX__ + { + static const char *unixroot = NULL; + static const char *last_shell = ""; + static int init = 0; + if (init == 0) + { + unixroot = getenv ("UNIXROOT"); + /* unixroot must be NULL or not empty */ + if (unixroot && unixroot[0] == '\0') unixroot = NULL; + init = 1; + } + + /* if we have an unixroot drive and if shell is not default_shell + (which means it's either cmd.exe or the test has already been + performed) and if shell is an absolute path without drive letter, + try whether it exists e.g.: if "/bin/sh" does not exist use + "$UNIXROOT/bin/sh" instead. */ + if (unixroot && shell && strcmp (shell, last_shell) != 0 + && (shell[0] == '/' || shell[0] == '\\')) + { + /* trying a new shell, check whether it exists */ + size_t size = strlen (shell); + char *buf = xmalloc (size + 7); + memcpy (buf, shell, size); + memcpy (buf + size, ".exe", 5); /* including the trailing '\0' */ + if (access (shell, F_OK) != 0 && access (buf, F_OK) != 0) + { + /* try the same for the unixroot drive */ + memmove (buf + 2, buf, size + 5); + buf[0] = unixroot[0]; + buf[1] = unixroot[1]; + if (access (buf, F_OK) == 0) + /* we have found a shell! */ + /* free(shell); */ + shell = buf; + else + free (buf); + } + else + free (buf); + } + } +#endif /* __EMX__ */ + + shellflags = allocated_variable_expand_for_file ("$(.SHELLFLAGS)", file); + ifs = allocated_variable_expand_for_file ("$(IFS)", file); + + warn_undefined_variables_flag = save; + } + +# ifdef CONFIG_WITH_KMK_BUILTIN + /* If it's a kmk_builtin command, make sure we're treated like a + unix shell and and don't get batch files. */ + if ( ( !unixy_shell + || batch_mode_shell +# ifdef WINDOWS32 + || no_default_sh_exe +# endif + ) + && line + && !strncmp (line, "kmk_builtin_", sizeof("kmk_builtin_") - 1)) + { + int saved_batch_mode_shell = batch_mode_shell; + int saved_unixy_shell = unixy_shell; +# ifdef WINDOWS32 + int saved_no_default_sh_exe = no_default_sh_exe; + no_default_sh_exe = 0; +# endif + unixy_shell = 1; + batch_mode_shell = 0; + argv = construct_command_argv_internal (line, restp, shell, shellflags, ifs, + cmd_flags, batch_filename); + batch_mode_shell = saved_batch_mode_shell; + unixy_shell = saved_unixy_shell; +# ifdef WINDOWS32 + no_default_sh_exe = saved_no_default_sh_exe; +# endif + } + else +# endif /* CONFIG_WITH_KMK_BUILTIN */ + argv = construct_command_argv_internal (line, restp, shell, shellflags, ifs, + cmd_flags, batch_filename); + + free (shell); + free (shellflags); + free (ifs); +#endif /* !VMS */ + return argv; +} + +#if !defined(HAVE_DUP2) && !defined(_AMIGA) +int +dup2 (int old, int new) +{ + int fd; + + (void) close (new); + EINTRLOOP (fd, dup (old)); + if (fd != new) + { + (void) close (fd); + errno = EMFILE; + return -1; + } + + return fd; +} +#endif /* !HAVE_DUP2 && !_AMIGA */ + +#ifdef CONFIG_WITH_PRINT_TIME_SWITCH +/* Prints the time elapsed while executing the commands for the given job. */ +void print_job_time (struct child *c) +{ + if ( !handling_fatal_signal + && print_time_min != -1 + && c->start_ts != -1) + { + big_int elapsed = nano_timestamp () - c->start_ts; + if (elapsed >= print_time_min * BIG_INT_C(1000000000)) + { + char buf[64]; + int len = format_elapsed_nano (buf, sizeof (buf), elapsed); + if (len > print_time_width) + print_time_width = len; + message (1, print_time_width + strlen (c->file->name), + _("%*s - %s"), print_time_width, buf, c->file->name); + } + } +} +#endif + +/* On VMS systems, include special VMS functions. */ + +#ifdef VMS +#include "vmsjobs.c" +#endif diff --git a/src/kmk/job.h b/src/kmk/job.h new file mode 100644 index 0000000..5cd25c2 --- /dev/null +++ b/src/kmk/job.h @@ -0,0 +1,175 @@ +/* Definitions for managing subprocesses in GNU Make. +Copyright (C) 1992-2016 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . */ + +#include "output.h" + +#ifdef HAVE_FCNTL_H +# include +#else +# include +#endif + +/* How to set close-on-exec for a file descriptor. */ + +#if !defined(F_SETFD) || !defined(F_GETFD) +# ifdef WINDOWS32 +# define CLOSE_ON_EXEC(_d) process_noinherit(_d) +# else +# define CLOSE_ON_EXEC(_d) +# endif +#else +# ifndef FD_CLOEXEC +# define FD_CLOEXEC 1 +# endif +# define CLOSE_ON_EXEC(_d) (void) fcntl ((_d), F_SETFD, FD_CLOEXEC) +#endif + +#ifdef NO_OUTPUT_SYNC +# define RECORD_SYNC_MUTEX(m) \ + O (error, NILF, \ + _("-O[TYPE] (--output-sync[=TYPE]) is not configured for this build.")); +#else +# ifdef WINDOWS32 +/* For emulations in w32/compat/posixfcn.c. */ +# define F_GETFD 1 +# define F_SETLKW 2 +/* Implementation note: None of the values of l_type below can be zero + -- they are compared with a static instance of the struct, so zero + means unknown/invalid, see w32/compat/posixfcn.c. */ +# define F_WRLCK 1 +# define F_UNLCK 2 + +struct flock + { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; + }; + +/* This type is actually a HANDLE, but we want to avoid including + windows.h as much as possible. */ +typedef intptr_t sync_handle_t; + +/* Public functions emulated/provided in posixfcn.c. */ +int fcntl (intptr_t fd, int cmd, ...); +# ifdef CONFIG_NEW_WIN_CHILDREN +intptr_t create_mutex (char *mtxname, size_t size); +# else +intptr_t create_mutex (void); +# endif +int same_stream (FILE *f1, FILE *f2); + +# define RECORD_SYNC_MUTEX(m) record_sync_mutex(m) +void record_sync_mutex (const char *str); +# ifdef CONFIG_NEW_WIN_CHILDREN +void prepare_mutex_handle_string (const char *mtxname); +# else +void prepare_mutex_handle_string (intptr_t hdl); +# endif +# else /* !WINDOWS32 */ + +typedef int sync_handle_t; /* file descriptor */ + +# define RECORD_SYNC_MUTEX(m) (void)(m) + +# endif +#endif /* !NO_OUTPUT_SYNC */ + +/* Structure describing a running or dead child process. */ + +struct child + { + struct child *next; /* Link in the chain. */ + + struct file *file; /* File being remade. */ + + char **environment; /* Environment for commands. */ + char *sh_batch_file; /* Script file for shell commands */ + char **command_lines; /* Array of variable-expanded cmd lines. */ + char *command_ptr; /* Ptr into command_lines[command_line]. */ + +#ifdef VMS + char *comname; /* Temporary command file name */ + int efn; /* Completion event flag number */ + int cstatus; /* Completion status */ + int vms_launch_status; /* non-zero if lib$spawn, etc failed */ +#endif + + unsigned int command_line; /* Index into command_lines. */ + struct output output; /* Output for this child. */ + pid_t pid; /* Child process's ID number. */ + unsigned int remote:1; /* Nonzero if executing remotely. */ + unsigned int noerror:1; /* Nonzero if commands contained a '-'. */ + unsigned int good_stdin:1; /* Nonzero if this child has a good stdin. */ + unsigned int deleted:1; /* Nonzero if targets have been deleted. */ + unsigned int recursive:1; /* Nonzero for recursive command ('+' etc.) */ + unsigned int dontcare:1; /* Saved dontcare flag. */ + +#ifdef CONFIG_WITH_KMK_BUILTIN + unsigned int has_status:1; /* Nonzero if status is available. */ + int status; /* Status of the job. */ +#endif +#ifdef CONFIG_WITH_PRINT_TIME_SWITCH + big_int start_ts; /* nano_timestamp of the first command. */ +#endif + }; + +extern struct child *children; + +/* A signal handler for SIGCHLD, if needed. */ +RETSIGTYPE child_handler (int sig); +int is_bourne_compatible_shell(const char *path); +void new_job (struct file *file); +void reap_children (int block, int err); +void start_waiting_jobs (void); + +char **construct_command_argv (char *line, char **restp, struct file *file, + int cmd_flags, char** batch_file); + +#ifdef VMS +int child_execute_job (struct child *child, char *argv); +#else +# define FD_STDIN (fileno (stdin)) +# define FD_STDOUT (fileno (stdout)) +# define FD_STDERR (fileno (stderr)) +int child_execute_job (struct output *out, int good_stdin, char **argv, char **envp); +#endif + +#ifdef _AMIGA +void exec_command (char **argv) __attribute__ ((noreturn)); +#elif defined(__EMX__) +int exec_command (char **argv, char **envp); +#elif !defined(WINDOWS32) || !defined(CONFIG_NEW_WIN_CHILDREN) +void exec_command (char **argv, char **envp) __attribute__ ((noreturn)); +#endif + +extern unsigned int job_slots_used; + +void block_sigs (void); +#ifdef POSIX +void unblock_sigs (void); +#else +#ifdef HAVE_SIGSETMASK +extern int fatal_signal_mask; +#define unblock_sigs() sigsetmask (0) +#else +#define unblock_sigs() +#endif +#endif + +extern unsigned int jobserver_tokens; diff --git a/src/kmk/kbuild-object.c b/src/kmk/kbuild-object.c new file mode 100644 index 0000000..e295636 --- /dev/null +++ b/src/kmk/kbuild-object.c @@ -0,0 +1,1409 @@ +/* $Id: kbuild-object.c 3141 2018-03-14 21:58:32Z bird $ */ +/** @file + * kBuild objects. + */ + +/* + * Copyright (c) 2011-2014 knut st. osmundsen + * + * This file is part of kBuild. + * + * kBuild is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * kBuild is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with kBuild. If not, see + * + */ + +/* No GNU coding style here! */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include "makeint.h" +#include "filedef.h" +#include "variable.h" +#include "dep.h" +#include "debug.h" +#include "kbuild.h" + +#include +#include + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +#define WORD_IS(a_pszWord, a_cchWord, a_szWord2) \ + ( (a_cchWord) == sizeof(a_szWord2) - 1 && memcmp((a_pszWord), a_szWord2, sizeof(a_szWord2) - 1) == 0) + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** kBuild object type. */ +enum kBuildType +{ + kBuildType_Invalid, + kBuildType_Target, + kBuildType_Template, + kBuildType_Tool, + kBuildType_Sdk, + kBuildType_Unit +}; + +enum kBuildSeverity +{ + kBuildSeverity_Warning, + kBuildSeverity_Error, + kBuildSeverity_Fatal +}; + + +/** + * kBuild object data. + */ +struct kbuild_object +{ + /** The object type. */ + enum kBuildType enmType; + /** Object name length. */ + size_t cchName; + /** The bare name of the define. */ + char *pszName; + /** The file location where this define was declared. */ + floc FileLoc; + + /** Pointer to the next element in the global list. */ + struct kbuild_object *pGlobalNext; + + /** The variable set associated with this define. */ + struct variable_set_list *pVariables; + + /** The parent name, NULL if none. */ + char *pszParent; + /** The length of the parent name. */ + size_t cchParent; + /** Pointer to the parent. Resolved lazily, so it can be NULL even if we + * have a parent. */ + struct kbuild_object *pParent; + + /** The template, NULL if none. Only applicable to targets. Only covers the + * primary template, not target or type specific templates. + * @todo not sure if this is really necessary. */ + char const *pszTemplate; + + /** The variable prefix. */ + char *pszVarPrefix; + /** The length of the variable prefix. */ + size_t cchVarPrefix; +}; + + +/** + * The data we stack during eval. + */ +struct kbuild_eval_data +{ + /** Pointer to the element below us on the stack. */ + struct kbuild_eval_data *pStackDown; + /** Pointer to the object. */ + struct kbuild_object *pObj; + /** The saved current variable set, for restoring in kBuild-endef. */ + struct variable_set_list *pVariablesSaved; +}; + + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/** Linked list (LIFO) of kBuild defines. + * @todo use a hash! */ +static struct kbuild_object *g_pHeadKbObjs = NULL; +/** Stack of kBuild evalutation contexts. + * This is for dealing with potential recursive kBuild object definition, + * generally believed to only happen via $(eval ) or include similar. */ +struct kbuild_eval_data *g_pTopKbEvalData = NULL; + +/** Cached variable name '_TEMPLATE'. */ +static const char *g_pszVarNmTemplate = NULL; + +/** Zero if compatibility mode is disabled, non-zero if enabled. + * If explicitily enabled, the value will be greater than 1. */ +int g_fKbObjCompMode = 1; + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +static struct kbuild_object * +resolve_kbuild_object_parent(struct kbuild_object *pObj, int fQuiet); +static struct kbuild_object * +get_kbuild_object_parent(struct kbuild_object *pObj, enum kBuildSeverity enmSeverity); + +static struct kbuild_object * +parse_kbuild_object_variable_accessor(const char *pchExpr, size_t cchExpr, + enum kBuildSeverity enmSeverity, const floc *pFileLoc, + const char **ppchVarNm, size_t *pcchVarNm, enum kBuildType *penmType); + + +/** + * Initializes the kBuild object stuff. + * + * Requires the variable_cache to be initialized. + */ +void init_kbuild_object(void) +{ + g_pszVarNmTemplate = strcache2_add(&variable_strcache, STRING_SIZE_TUPLE("_TEMPLATE")); +} + + +/** + * Reports a problem with dynamic severity level. + * + * @param enmSeverity The severity level. + * @param pFileLoc The file location. + * @param pszFormat The format string. + * @param ... Arguments for the format string. + */ +static void kbuild_report_problem(enum kBuildSeverity enmSeverity, const floc *pFileLoc, + const char *pszFormat, ...) +{ + char szBuf[8192]; + va_list va; + + va_start(va, pszFormat); +#ifdef _MSC_VER + _vsnprintf(szBuf, sizeof(szBuf), pszFormat, va); +#else + vsnprintf(szBuf, sizeof(szBuf), pszFormat, va); +#endif + va_end(va); + + switch (enmSeverity) + { + case kBuildSeverity_Warning: + OS(message, 0, "%s", szBuf); + break; + case kBuildSeverity_Error: + OS(error, pFileLoc, "%s", szBuf); + break; + default: + case kBuildSeverity_Fatal: + OS(fatal, pFileLoc, "%s", szBuf); + break; + } +} + + +static const char * +eval_kbuild_type_to_string(enum kBuildType enmType) +{ + switch (enmType) + { + case kBuildType_Target: return "target"; + case kBuildType_Template: return "template"; + case kBuildType_Tool: return "tool"; + case kBuildType_Sdk: return "sdk"; + case kBuildType_Unit: return "unit"; + default: + case kBuildType_Invalid: return "invalid"; + } +} + +/** + * Gets the length of the string representation of the given type. + * + * @returns The string length. + * @param enmType The kBuild object type in question. + */ +static unsigned +eval_kbuild_type_to_string_length(enum kBuildType enmType) +{ + switch (enmType) + { + case kBuildType_Target: return sizeof("target") - 1; + case kBuildType_Template: return sizeof("template") - 1; + case kBuildType_Tool: return sizeof("tool") - 1; + case kBuildType_Sdk: return sizeof("sdk") - 1; + case kBuildType_Unit: return sizeof("unit") - 1; + default: + case kBuildType_Invalid: return sizeof("invalid") - 1; + } +} + +/** + * Converts a string into an kBuild object type. + * + * @returns The type on success, kBuildType_Invalid on failure. + * @param pchWord The pchWord. Not necessarily zero terminated. + * @param cchWord The length of the word. + */ +static enum kBuildType +eval_kbuild_type_from_string(const char *pchWord, size_t cchWord) +{ + if (cchWord >= 3) + { + if (*pchWord == 't') + { + if (WORD_IS(pchWord, cchWord, "target")) + return kBuildType_Target; + if (WORD_IS(pchWord, cchWord, "template")) + return kBuildType_Template; + if (WORD_IS(pchWord, cchWord, "tool")) + return kBuildType_Tool; + } + else + { + if (WORD_IS(pchWord, cchWord, "sdk")) + return kBuildType_Sdk; + if (WORD_IS(pchWord, cchWord, "unit")) + return kBuildType_Unit; + } + } + + return kBuildType_Invalid; +} + + + +#if 0 /* unused */ +/** + * Helper function for caching variable name strings. + * + * @returns The string cache variable name. + * @param pszName The variable name. + * @param ppszCache Cache variable, static or global. Initialize to + * NULL. + */ +static const char * +kbuild_variable_name(const char *pszName, const char **ppszCache) +{ + const char *pszRet = *ppszCache; + if (!pszRet) + *ppszCache = pszRet = strcache2_add(&variable_strcache, pszName, strlen(pszName)); + return pszRet; +} +#endif + +static struct kbuild_object * +lookup_kbuild_object(enum kBuildType enmType, const char *pchName, size_t cchName) +{ + /* Linear lookup for now. */ + struct kbuild_object *pCur = g_pHeadKbObjs; + while (pCur) + { + if ( pCur->enmType == enmType + && pCur->cchName == cchName + && !memcmp(pCur->pszName, pchName, cchName)) + return pCur; + pCur = pCur->pGlobalNext; + } + return NULL; +} + + +/** @name Defining and modifying variables + * @{ + */ + +/** + * Checks if the variable name is valid. + * + * @returns 1 if valid, 0 if not. + * @param pchName The variable name. + * @param cchName The length of the variable name. + */ +static int +is_valid_kbuild_object_variable_name(const char *pchName, size_t cchName) +{ + if (cchName > 0) + { + if (!memchr(pchName, '[', cchName)) + { + /** @todo more? */ + return 1; + } + } + return 0; +} + +static const char * +kbuild_replace_special_accessors(const char *pchValue, size_t *pcchValue, int *pfDuplicateValue, + const floc *pFileLoc) +{ + size_t cchValue = *pcchValue; + size_t cbAllocated = *pfDuplicateValue ? 0 : cchValue + 1; + + /* + * Loop thru each potential special accessor occurance in the string. + * + * Unfortunately, we don't have a strnstr function in the C library, so + * we'll using memchr and doing a few more rounds in this loop. + */ + size_t cchLeft = cchValue; + char *pchLeft = (char *)pchValue; + for (;;) + { + int fSuper; + char *pch = (char *)memchr(pchLeft, '$', cchLeft); + if (!pch) + break; + + pch++; + cchLeft -= pch - pchLeft; + pchLeft = pch; + + /* [@self] is the shorter, quit if there isn't enough room for even it. */ + if (cchLeft < sizeof("([@self]") - 1) + break; + + /* We don't care how many dollars there are in front of a special accessor. */ + if (*pchLeft == '$') + { + do + { + cchLeft--; + pchLeft++; + } while (cchLeft >= sizeof("([@self]") - 1 && *pchLeft == '$'); + if (cchLeft < sizeof("([@self]") - 1) + break; + } + + /* Is it a special accessor? */ + if ( pchLeft[2] != '@' + || pchLeft[1] != '[' + || pchLeft[0] != '(') + continue; + pchLeft += 2; + cchLeft -= 2; + if (!memcmp(pchLeft, STRING_SIZE_TUPLE("@self]"))) + fSuper = 0; + else if ( cchLeft >= sizeof("@super]") + && !memcmp(pchLeft, STRING_SIZE_TUPLE("@super]"))) + fSuper = 1; + else + continue; + + /* + * We've got something to replace. First figure what with and then + * resize the value buffer. + */ + if (g_pTopKbEvalData) + { + struct kbuild_object *pObj = g_pTopKbEvalData->pObj; + size_t const cchSpecial = fSuper ? sizeof("@super") - 1 : sizeof("@self") - 1; + size_t cchName; + size_t cchType; + long cchDelta; + const char *pszName; + + if (fSuper) + { + pObj = get_kbuild_object_parent(pObj, kBuildSeverity_Error); + if (!pObj) + continue; + } + pszName = pObj->pszName; + cchName = pObj->cchName; + cchType = eval_kbuild_type_to_string_length(pObj->enmType); + cchDelta = cchType + 1 + cchName - cchSpecial; + + if (cchValue + cchDelta >= cbAllocated) + { + size_t offLeft = pchLeft - pchValue; + char *pszNewValue; + + cbAllocated = cchValue + cchDelta + 1; + if (cchValue < 1024) + cbAllocated = (cbAllocated + 31) & ~(size_t)31; + else + cbAllocated = (cbAllocated + 255) & ~(size_t)255; + pszNewValue = (char *)xmalloc(cbAllocated); + + memcpy(pszNewValue, pchValue, offLeft); + memcpy(pszNewValue + offLeft + cchSpecial + cchDelta, + pchLeft + cchSpecial, + cchLeft - cchSpecial + 1); + + if (*pfDuplicateValue == 0) + free((char *)pchValue); + else + *pfDuplicateValue = 0; + + pchValue = pszNewValue; + pchLeft = pszNewValue + offLeft; + } + else + { + assert(*pfDuplicateValue == 0); + memmove(pchLeft + cchSpecial + cchDelta, + pchLeft + cchSpecial, + cchLeft - cchSpecial + 1); + } + + cchLeft += cchDelta; + cchValue += cchDelta; + *pcchValue = cchValue; + + memcpy(pchLeft, eval_kbuild_type_to_string(pObj->enmType), cchType); + pchLeft += cchType; + *pchLeft++ = '@'; + memcpy(pchLeft, pszName, cchName); + pchLeft += cchName; + cchLeft -= cchType + 1 + cchName; + } + else + error(pFileLoc, 20, _("The '$([%.*s...' accessor can only be used in the context of a kBuild object"), + (int)MIN(cchLeft, 20), pchLeft); + } + + return pchValue; +} + +static struct variable * +define_kbuild_object_variable_cached(struct kbuild_object *pObj, const char *pszName, + const char *pchValue, size_t cchValue, + int fDuplicateValue, enum variable_origin enmOrigin, + int fRecursive, int fNoSpecialAccessors, const floc *pFileLoc) +{ + struct variable *pVar; + size_t cchName = strcache2_get_len(&variable_strcache, pszName); + + if (fRecursive && !fNoSpecialAccessors) + pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc); + + pVar = define_variable_in_set(pszName, cchName, + pchValue, cchValue, fDuplicateValue, + enmOrigin, fRecursive, + pObj->pVariables->set, + pFileLoc); + + /* Single underscore prefixed variables gets a global alias. */ + if ( pszName[0] == '_' + && pszName[1] != '_' + && g_fKbObjCompMode) + { + struct variable *pAlias; + size_t cchPrefixed = pObj->cchVarPrefix + cchName; + char *pszPrefixed = xmalloc(cchPrefixed + 1); + memcpy(pszPrefixed, pObj->pszVarPrefix, pObj->cchVarPrefix); + memcpy(&pszPrefixed[pObj->cchVarPrefix], pszName, cchName); + pszPrefixed[cchPrefixed] = '\0'; + + pAlias = define_variable_alias_in_set(pszPrefixed, cchPrefixed, pVar, enmOrigin, + &global_variable_set, pFileLoc); + if (!pAlias->alias) + OS(error, pFileLoc, _("Error defining alias '%s'"), pszPrefixed); + } + + return pVar; +} + +#if 0 +struct variable * +define_kbuild_object_variable(struct kbuild_object *pObj, const char *pchName, size_t cchName, + const char *pchValue, size_t cchValue, + int fDuplicateValue, enum variable_origin enmOrigin, + int fRecursive, const floc *pFileLoc) +{ + return define_kbuild_object_variable_cached(pObj, strcache2_add(&variable_strcache, pchName, cchName), + pchValue, cchValue, + fDuplicateValue, enmOrigin, + fRecursive, pFileLoc); +} +#endif + +/** + * Try define a kBuild object variable via a possible accessor + * ([type@object]var). + * + * @returns Pointer to the defined variable on success. + * @retval VAR_NOT_KBUILD_ACCESSOR if it isn't an accessor. + * + * @param pchName The variable name, not cached. + * @param cchName The variable name length. This will not be ~0U. + * @param pszValue The variable value. If @a fDuplicateValue is clear, + * this should be assigned as the actual variable + * value, otherwise it will be duplicated. In the + * latter case it might not be properly null + * terminated. + * @param cchValue The value length. + * @param fDuplicateValue Whether @a pszValue need to be duplicated on the + * heap or is already there. + * @param enmOrigin The variable origin. + * @param fRecursive Whether it's a recursive variable. + * @param pFileLoc The location of the variable definition. + */ +struct variable * +try_define_kbuild_object_variable_via_accessor(const char *pchName, size_t cchName, + const char *pszValue, size_t cchValue, int fDuplicateValue, + enum variable_origin enmOrigin, int fRecursive, + floc const *pFileLoc) +{ + struct kbuild_object *pObj; + const char *pchVarNm; + size_t cchVarNm; + + pObj = parse_kbuild_object_variable_accessor(pchName, cchName, kBuildSeverity_Fatal, pFileLoc, + &pchVarNm, &cchVarNm, NULL); + if (pObj != KOBJ_NOT_KBUILD_ACCESSOR) + { + assert(pObj != NULL); + if (!is_valid_kbuild_object_variable_name(pchVarNm, cchVarNm)) + fatal(pFileLoc, cchVarNm + cchName, _("Invalid kBuild object variable name: '%.*s' ('%.*s')"), + (int)cchVarNm, pchVarNm, (int)cchName, pchName); + return define_kbuild_object_variable_cached(pObj, strcache2_add(&variable_strcache, pchVarNm, cchVarNm), + pszValue, cchValue, fDuplicateValue, enmOrigin, fRecursive, + 0 /*fNoSpecialAccessors*/, pFileLoc); + } + + return VAR_NOT_KBUILD_ACCESSOR; +} + +/** + * Define a kBuild object variable in the topmost kBuild object. + * + * This won't be an variable accessor. + * + * @returns Pointer to the defined variable on success. + * + * @param pchName The variable name, not cached. + * @param cchName The variable name length. This will not be ~0U. + * @param pszValue The variable value. If @a fDuplicateValue is clear, + * this should be assigned as the actual variable + * value, otherwise it will be duplicated. In the + * latter case it might not be properly null + * terminated. + * @param cchValue The value length. + * @param fDuplicateValue Whether @a pszValue need to be duplicated on the + * heap or is already there. + * @param enmOrigin The variable origin. + * @param fRecursive Whether it's a recursive variable. + * @param pFileLoc The location of the variable definition. + */ +struct variable * +define_kbuild_object_variable_in_top_obj(const char *pchName, size_t cchName, + const char *pszValue, size_t cchValue, int fDuplicateValue, + enum variable_origin enmOrigin, int fRecursive, + floc const *pFileLoc) +{ + assert(g_pTopKbEvalData != NULL); + + if (!is_valid_kbuild_object_variable_name(pchName, cchName)) + fatal(pFileLoc, cchName, _("Invalid kBuild object variable name: '%.*s'"), (int)cchName, pchName); + + return define_kbuild_object_variable_cached(g_pTopKbEvalData->pObj, strcache2_add(&variable_strcache, pchName, cchName), + pszValue, cchValue, fDuplicateValue, enmOrigin, fRecursive, + 0 /*fNoSpecialAccessors*/, pFileLoc); +} + +/** + * Implements appending and prepending to a kBuild object variable. + * + * The variable is either accessed thru an accessor or by the topmost kBuild + * object. + * + * @returns Pointer to the defined variable on success. + * + * @param pchName The variable name, not cached. + * @param cchName The variable name length. This will not be ~0U. + * @param pszValue The variable value. Must be duplicated. + * @param cchValue The value length. + * @param fSimpleValue Whether we've already figured that it's a simple + * value. This is for optimizing appending/prepending + * to an existing simple value variable. + * @param enmOrigin The variable origin. + * @param fAppend Append if set, prepend if clear. + * @param pFileLoc The location of the variable definition. + */ +struct variable * +kbuild_object_variable_pre_append(const char *pchName, size_t cchName, + const char *pchValue, size_t cchValue, int fSimpleValue, + enum variable_origin enmOrigin, int fAppend, + const floc *pFileLoc) +{ + struct kbuild_object *pObj; + struct variable VarKey; + + /* + * Resolve the relevant kBuild object first. + */ + if (cchName > 3 && pchName[0] == '[') + { + const char *pchVarNm; + size_t cchVarNm; + pObj = parse_kbuild_object_variable_accessor(pchName, cchName, kBuildSeverity_Fatal, pFileLoc, + &pchVarNm, &cchVarNm, NULL); + if (pObj != KOBJ_NOT_KBUILD_ACCESSOR) + { + pchName = pchVarNm; + cchName = cchVarNm; + } + else + pObj = g_pTopKbEvalData->pObj; + } + else + pObj = g_pTopKbEvalData->pObj; + + /* + * Make sure the variable name is valid. Raise fatal error if not. + */ + if (!is_valid_kbuild_object_variable_name(pchName, cchName)) + fatal(pFileLoc, cchName, _("Invalid kBuild object variable name: '%.*s'"), (int)cchName, pchName); + + /* + * Get the cached name and look it up in the object's variables. + */ + VarKey.name = strcache2_lookup(&variable_strcache, pchName, cchName); + if (VarKey.name) + { + struct variable *pVar; + + VarKey.length = cchName; + pVar = (struct variable *)hash_find_item_strcached(&pObj->pVariables->set->table, &VarKey); + if (pVar) + { + /* Append/prepend to existing variable. */ + int fDuplicateValue = 1; + if (pVar->recursive && !fSimpleValue) + pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc); + + pVar = do_variable_definition_append(pFileLoc, pVar, pchValue, cchValue, fSimpleValue, enmOrigin, fAppend); + + if (fDuplicateValue == 0) + free((char *)pchValue); + return pVar; + } + + /* + * Not found. Check ancestors if the 'override' directive isn't applied. + */ + if (pObj->pszParent && enmOrigin != o_override) + { + struct kbuild_object *pParent = pObj; + for (;;) + { + pParent = resolve_kbuild_object_parent(pParent, 0 /*fQuiet*/); + if (!pParent) + break; + + pVar = (struct variable *)hash_find_item_strcached(&pParent->pVariables->set->table, &VarKey); + if (pVar) + { + if (pVar->value_length != ~0U) + assert(pVar->value_length == strlen(pVar->value)); + else + pVar->value_length = strlen(pVar->value); + + /* + * Combine the two values and define the variable in the + * specified child object. We must disregard 'origin' a + * little here, so we must do the gritty stuff our selves. + */ + if ( pVar->recursive + || fSimpleValue + || !cchValue + || memchr(pchValue, '$', cchValue) == NULL ) + { + int fDuplicateValue = 1; + size_t cchNewValue; + char *pszNewValue; + char *pszTmp; + + /* Just join up the two values. */ + if (pVar->recursive && !fSimpleValue) + pchValue = kbuild_replace_special_accessors(pchValue, &cchValue, &fDuplicateValue, pFileLoc); + if (pVar->value_length == 0) + { + cchNewValue = cchValue; + pszNewValue = xstrndup(pchValue, cchValue); + } + else if (!cchValue) + { + cchNewValue = pVar->value_length; + pszNewValue = xmalloc(cchNewValue + 1); + memcpy(pszNewValue, pVar->value, cchNewValue + 1); + } + else + { + cchNewValue = pVar->value_length + 1 + cchValue; + pszNewValue = xmalloc(cchNewValue + 1); + if (fAppend) + { + memcpy(pszNewValue, pVar->value, pVar->value_length); + pszTmp = pszNewValue + pVar->value_length; + *pszTmp++ = ' '; + memcpy(pszTmp, pchValue, cchValue); + pszTmp[cchValue] = '\0'; + } + else + { + memcpy(pszNewValue, pchValue, cchValue); + pszTmp = pszNewValue + cchValue; + *pszTmp++ = ' '; + memcpy(pszNewValue, pVar->value, pVar->value_length); + pszTmp[pVar->value_length] = '\0'; + } + } + + /* Define the new variable in the child. */ + pVar = define_kbuild_object_variable_cached(pObj, VarKey.name, + pszNewValue, cchNewValue, 0 /*fDuplicateValue*/, + enmOrigin, pVar->recursive, 1 /*fNoSpecialAccessors*/, + pFileLoc); + if (fDuplicateValue == 0) + free((char *)pchValue); + } + else + { + /* Lazy bird: Copy the variable from the ancestor and + then do a normal append/prepend on it. */ + pVar = define_kbuild_object_variable_cached(pObj, VarKey.name, + pVar->value, pVar->value_length, 1 /*fDuplicateValue*/, + enmOrigin, pVar->recursive, 1 /*fNoSpecialAccessors*/, + pFileLoc); + append_expanded_string_to_variable(pVar, pchValue, cchValue, fAppend); + } + return pVar; + } + } + } + } + else + VarKey.name = strcache2_add(&variable_strcache, pchName, cchName); + + /* Variable not found. */ + return define_kbuild_object_variable_cached(pObj, VarKey.name, + pchValue, cchValue, 1 /*fDuplicateValue*/, enmOrigin, + 1 /*fRecursive */, 0 /*fNoSpecialAccessors*/, pFileLoc); +} + +/** @} */ + + +static char * +allocate_expanded_next_token(const char **ppszCursor, const char *pszEos, size_t *pcchToken, int fStrip) +{ + unsigned int cchToken; + char *pszToken = find_next_token_eos(ppszCursor, pszEos, &cchToken); + if (pszToken) + { + pszToken = allocated_variable_expand_2(pszToken, cchToken, &cchToken); + if (pszToken) + { + if (fStrip) + { + unsigned int off = 0; + while (MY_IS_BLANK(pszToken[off])) + off++; + if (off) + { + cchToken -= off; + memmove(pszToken, &pszToken[off], cchToken + 1); + } + + while (cchToken > 0 && MY_IS_BLANK(pszToken[cchToken - 1])) + pszToken[--cchToken] = '\0'; + } + + assert(cchToken == strlen(pszToken)); + if (pcchToken) + *pcchToken = cchToken; + return pszToken; + } + } + + if (pcchToken) + *pcchToken = 0; + return NULL; +} + +static struct kbuild_object * +resolve_kbuild_object_parent(struct kbuild_object *pObj, int fQuiet) +{ + if ( !pObj->pParent + && pObj->pszParent) + { + struct kbuild_object *pCur = g_pHeadKbObjs; + while (pCur) + { + if ( pCur->enmType == pObj->enmType + && !strcmp(pCur->pszName, pObj->pszParent)) + { + if ( pCur->pszParent + && ( pCur->pParent == pObj + || !strcmp(pCur->pszParent, pObj->pszName)) ) + OSS(fatal, &pObj->FileLoc, _("'%s' and '%s' are both trying to be each other children..."), + pObj->pszName, pCur->pszName); + + pObj->pParent = pCur; + pObj->pVariables->next = pObj->pVariables; + return pCur; + } + + pCur = pCur->pGlobalNext; + } + + /* Not found. */ + if (!fQuiet) + OSS(error, &pObj->FileLoc, _("Could not locate parent '%s' of '%s'"), pObj->pszParent, pObj->pszName); + } + return pObj->pParent; +} + +/** + * Get the parent of the given object, it is expected to have one. + * + * @returns Pointer to the parent. NULL if we survive failure. + * @param pObj The kBuild object. + * @param enmSeverity The severity of a missing parent. + */ +static struct kbuild_object * +get_kbuild_object_parent(struct kbuild_object *pObj, enum kBuildSeverity enmSeverity) +{ + struct kbuild_object *pParent = pObj->pParent; + if (pParent) + return pParent; + + pParent = resolve_kbuild_object_parent(pObj, 1 /*fQuiet - complain below */); + if (pParent) + return pParent; + + if (pObj->pszParent) + kbuild_report_problem(enmSeverity, &pObj->FileLoc, + _("Could not local parent '%s' for kBuild object '%s'"), + pObj->pszParent, pObj->pszName); + else + kbuild_report_problem(enmSeverity, &pObj->FileLoc, + _("kBuild object '%s' has no parent ([@super])"), + pObj->pszName); + return NULL; +} + +static int +eval_kbuild_define_xxxx(struct kbuild_eval_data **ppData, const floc *pFileLoc, + const char *pszLine, const char *pszEos, int fIgnoring, enum kBuildType enmType) +{ + unsigned int cch; + char ch; + char *psz; + const char *pszPrefix; + struct kbuild_object *pObj; + struct kbuild_eval_data *pData; + + if (fIgnoring) + return 0; + + /* + * Create a new kBuild object. + */ + pObj = xmalloc(sizeof(*pObj)); + pObj->enmType = enmType; + pObj->pszName = NULL; + pObj->cchName = 0; + pObj->FileLoc = *pFileLoc; + + pObj->pGlobalNext = g_pHeadKbObjs; + g_pHeadKbObjs = pObj; + + pObj->pVariables = create_new_variable_set(); + + pObj->pszParent = NULL; + pObj->cchParent = 0; + pObj->pParent = NULL; + + pObj->pszTemplate = NULL; + + pObj->pszVarPrefix = NULL; + pObj->cchVarPrefix = 0; + + /* + * The first word is the name. + */ + pObj->pszName = allocate_expanded_next_token(&pszLine, pszEos, &pObj->cchName, 1 /*strip*/); + if (!pObj->pszName || !*pObj->pszName) + O(fatal, pFileLoc, _("The kBuild define requires a name")); + + psz = pObj->pszName; + while ((ch = *psz++) != '\0') + if (!isgraph(ch)) + { + OSS(error, pFileLoc, _("The 'kBuild-define-%s' name '%s' contains one or more invalid characters"), + eval_kbuild_type_to_string(enmType), pObj->pszName); + break; + } + + /* + * Calc the variable prefix. + */ + switch (enmType) + { + case kBuildType_Target: pszPrefix = ""; break; + case kBuildType_Template: pszPrefix = "TEMPLATE_"; break; + case kBuildType_Tool: pszPrefix = "TOOL_"; break; + case kBuildType_Sdk: pszPrefix = "SDK_"; break; + case kBuildType_Unit: pszPrefix = "UNIT_"; break; + default: + ON(fatal, pFileLoc, _("enmType=%d"), enmType); + return -1; + } + cch = strlen(pszPrefix); + pObj->cchVarPrefix = cch + pObj->cchName; + pObj->pszVarPrefix = xmalloc(pObj->cchVarPrefix + 1); + memcpy(pObj->pszVarPrefix, pszPrefix, cch); + memcpy(&pObj->pszVarPrefix[cch], pObj->pszName, pObj->cchName); + + /* + * Parse subsequent words. + */ + psz = find_next_token_eos(&pszLine, pszEos, &cch); + while (psz) + { + if (WORD_IS(psz, cch, "extending")) + { + /* Inheritance directive. */ + if (pObj->pszParent != NULL) + O(fatal, pFileLoc, _("'extending' can only occure once")); + pObj->pszParent = allocate_expanded_next_token(&pszLine, pszEos, &pObj->cchParent, 1 /*strip*/); + if (!pObj->pszParent || !*pObj->pszParent) + O(fatal, pFileLoc, _("'extending' requires a parent name")); + } + else if (WORD_IS(psz, cch, "using")) + { + char *pszTemplate; + size_t cchTemplate; + + /* Template directive. */ + if (enmType != kBuildType_Target) + O(fatal, pFileLoc, _("'using