diff options
656 files changed, 14869 insertions, 10875 deletions
diff --git a/ChangeLog b/ChangeLog index 20e2628b3bed..847c2e4c0f90 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,243 @@ +2020-09-02 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200902 + Merge with NetBSD make, pick up + o use make_stat to ensure no confusion over valid fields + returned by cached_stat + o var.c: make VarQuote const-correct + o add unit tests for .for + +2020-09-01 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200901 + Merge with NetBSD make, pick up + o rename Hash_Table fields + o make data types in Dir_HasWildcards more precise + +2020-08-31 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200831 + Merge with NetBSD make, pick up + o suff.c: fix unbalanced Lst_Open/Lst_Close in SuffFindCmds + o lst.c: Lst_Open renable assert that list isn't open + o unit test for .TARGET dependent flags + o var.c: fix aliasing bug in VarUniq + o more unit tests for :u + +2020-08-30 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200830 + Merge with NetBSD make, pick up + o allow for strict type checking for Boolean + o Var_Parse never returns NULL + o Var_Subst never returns NULL + o Lst_Find now takes boolean match function + o rename Lst_Memeber to Lst_FindDatum + o rename LstNode functions to match their type + o rename GNode.iParents to implicitParents + o fix assertion failure for .SUFFIXES in archives + o compat.c: clean up documentation for CompatInterrupt and Compat_Run + remove unreachable code from CompatRunCommand + o main.c: simplify getBoolean + o stc.c: replace brk_string with simpler Str_Words + o suff.c: add debug macros + +2020-08-28 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200828 + Merge with NetBSD make, pick up + o lst.c: inline LstIsValid and LstNodeIsValid + o remove trailing S from Lst function names after migration complete + o more comment cleanup/clarification + o suff.c: clean up suffix handling + o more unit tests + +2020-08-26 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200826 + Merge with NetBSD make, pick up + o enum.c: distinguish between bitsets containing flags and + ordinary enums + o var.c: fix error message for ::!= modifier with shell error + o fix bugs in -DCLEANUP mode + +2020-08-24 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200824 + Merge with NetBSD make, pick up + o in debug mode, print GNode details in symbols + +2020-08-23 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200823 + Merge with NetBSD make, pick up + o lst.c: more asserts, + make args to Lst_Find match others. + o var.c: pass flags to VarAdd + o arch.c: use Buffer + o str.c: brk_string return size_t for nwords + o more unit tests + +2020-08-22 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): + Merge with NetBSD make, pick up + o var.c: support for read-only variables eg .SHELL + being the shell used to run scripts. + o lst.c: more simplification + o more documentation and style cleanup + o more unit tests + o ensure unit-test/Makefile is run by TEST_MAKE + o reduce duplication of header inclusion + +2020-08-21 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200821 + Merge with NetBSD make, pick up + o lst.c: revert invalid assertion - but document it + o dir.c: split Dir_Init into two functions + +2020-08-20 Simon J Gerraty <sjg@beast.crufty.net> + + * lst.c: needs inttypes.h on Linux + + * VERSION (_MAKE_VERSION): 20200820 + Merge with NetBSD make, pick up + o make.1: clarify some passages + o var.c: more cleanup, clarify comments + o make_malloc.c: remove unreachable code + o cond.c: make CondGetString easier to debug + o simplify list usage + o unit-tests: more + +2020-08-16 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200816 + Merge with NetBSD make, pick up + o refactor unit-tests to be more fine grained + not all tests moved yet + +2020-08-14 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200814 + Merge with NetBSD make, pick up + o more str_concat variants + o more enums for flags + o var.c: cleanup for higher warnings level + +2020-08-10 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200810 + Merge with NetBSD make, pick up + o more unit tests + o general comment and style cleanup + +2020-08-08 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200808 + Merge with NetBSD make, pick up + o enum.[ch]: streamline, enums for use in flags and debug output + o cond.c: cleanup + o var.c: reduce duplicate code for modifiers + debug logging for Var_Parse + more detailed debug output + o more unit tests + +2020-08-06 Simon J Gerraty <sjg@beast.crufty.net> + + * unit-tests/Makefile: -r for recursive and include Makefile.inc + so I can run tests in meta mode + supress extra noise if in meta mode + + * VERSION (_MAKE_VERSION): 20200806 + Merge with NetBSD make, pick up + o parse.c: remove VARE_WANTRES for LINT + we just want to check parsing (for now). + +2020-08-05 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200805 + Merge with NetBSD make, pick up + o make.1: Rework the description of dependence operators + +2020-08-03 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200803 + Merge with NetBSD make, pick up + o revert some C99 usage, for max portability + o unit-tests/lint + +2020-08-02 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200802 + Merge with NetBSD make, pick up + o more unit tests + +2020-08-01 Simon J Gerraty <sjg@beast.crufty.net> + + * Remove NetBSD specific plumbing from unit-tests/Makefile + + * VERSION (_MAKE_VERSION): 20200801 + Merge with NetBSD make, pick up + o make Var_Value return const + o size_t for buf sizes + o optimize some buffer operations - avoid strlen + +2020-07-31 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200731 + Merge with NetBSD make, pick up + o var.c: fix undefinded behavior for incomplete :t modifier + fixes unit-test/moderrs on Ubuntu + o parse.c: When parsing variable assignments other than := + if DEBUG(LINT) test substition of value, so we get a file and + line number in the resulting error. + o dir.c: fix parsing of nested braces in dependency lines + add unit-tests + +2020-07-30 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200730 + Merge with NetBSD make, pick up + o var.c: minor cleanup + o unit-tests: more tests to improve code coverage + +2020-07-28 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200728 + Merge with NetBSD make, pick up + o var.c: more optimizations + +2020-07-26 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200726 + Merge with NetBSD make, pick up + o collapse lsd.lib into lst.c - reduce code size and allow inlining + o lots of function comment updates + o var.c: more optimizations + o make return of Var_Parse const + +2020-07-20 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200720 + Merge with NetBSD make, pick up + o DEBUG_HASH report stats at end and tone down the noise + o var.c: each flag type gets its own prefix. + move SysV string matching to var.c + make ampersand in ${VAR:from=to&} an ordinary character + cleanup and simplify implementation of modifiers + o make.1: move documentation for assignment modifiers + +2020-07-18 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20200718 + Merge with NetBSD make, pick up + o DEBUG_HASH to see how well the hash tables are working + +2020-07-11 Simon J Gerraty <sjg@beast.crufty.net> + + * bsd.after-import.mk: make sure we update unit-tests/Makefile + 2020-07-10 Simon J Gerraty <sjg@beast.crufty.net> * configure.in: use AC_INCLUDES_DEFAULT rather than AC_HEADER_STDC @@ -23,6 +23,8 @@ configure.in dir.c dir.h dirname.c +enum.c +enum.h filemon/filemon.h filemon/filemon_dev.c filemon/filemon_ktrace.c @@ -34,36 +36,8 @@ hash.h install-sh job.c job.h +lst.c lst.h -lst.lib/Makefile -lst.lib/lstAppend.c -lst.lib/lstAtEnd.c -lst.lib/lstAtFront.c -lst.lib/lstClose.c -lst.lib/lstConcat.c -lst.lib/lstDatum.c -lst.lib/lstDeQueue.c -lst.lib/lstDestroy.c -lst.lib/lstDupl.c -lst.lib/lstEnQueue.c -lst.lib/lstFind.c -lst.lib/lstFindFrom.c -lst.lib/lstFirst.c -lst.lib/lstForEach.c -lst.lib/lstForEachFrom.c -lst.lib/lstInit.c -lst.lib/lstInsert.c -lst.lib/lstInt.h -lst.lib/lstIsAtEnd.c -lst.lib/lstIsEmpty.c -lst.lib/lstLast.c -lst.lib/lstMember.c -lst.lib/lstNext.c -lst.lib/lstOpen.c -lst.lib/lstPrev.c -lst.lib/lstRemove.c -lst.lib/lstReplace.c -lst.lib/lstSucc.c machine.sh main.c make-bootstrap.sh.in @@ -88,7 +62,6 @@ ranlib.h realpath.c setenv.c sigcompat.c -sprite.h str.c stresep.c strlcpy.c @@ -100,22 +73,234 @@ trace.c trace.h unit-tests/Makefile unit-tests/Makefile.config.in +unit-tests/archive.exp +unit-tests/archive.mk +unit-tests/archive-suffix.exp +unit-tests/archive-suffix.mk +unit-tests/cmd-interrupt.exp +unit-tests/cmd-interrupt.mk +unit-tests/cmdline.exp +unit-tests/cmdline.mk unit-tests/comment.exp unit-tests/comment.mk +unit-tests/cond-cmp-numeric-eq.exp +unit-tests/cond-cmp-numeric-eq.mk +unit-tests/cond-cmp-numeric-ge.exp +unit-tests/cond-cmp-numeric-ge.mk +unit-tests/cond-cmp-numeric-gt.exp +unit-tests/cond-cmp-numeric-gt.mk +unit-tests/cond-cmp-numeric-le.exp +unit-tests/cond-cmp-numeric-le.mk +unit-tests/cond-cmp-numeric-lt.exp +unit-tests/cond-cmp-numeric-lt.mk +unit-tests/cond-cmp-numeric-ne.exp +unit-tests/cond-cmp-numeric-ne.mk +unit-tests/cond-cmp-numeric.exp +unit-tests/cond-cmp-numeric.mk +unit-tests/cond-cmp-string.exp +unit-tests/cond-cmp-string.mk +unit-tests/cond-func.exp +unit-tests/cond-func.mk +unit-tests/cond-func-commands.exp +unit-tests/cond-func-commands.mk +unit-tests/cond-func-defined.exp +unit-tests/cond-func-defined.mk +unit-tests/cond-func-empty.exp +unit-tests/cond-func-empty.mk +unit-tests/cond-func-exists.exp +unit-tests/cond-func-exists.mk +unit-tests/cond-func-make.exp +unit-tests/cond-func-make.mk +unit-tests/cond-func-target.exp +unit-tests/cond-func-target.mk +unit-tests/cond-late.exp +unit-tests/cond-late.mk +unit-tests/cond-op-and.exp +unit-tests/cond-op-and.mk +unit-tests/cond-op-not.exp +unit-tests/cond-op-not.mk +unit-tests/cond-op-or.exp +unit-tests/cond-op-or.mk +unit-tests/cond-op-parentheses.exp +unit-tests/cond-op-parentheses.mk +unit-tests/cond-op.exp +unit-tests/cond-op.mk +unit-tests/cond-short.exp +unit-tests/cond-short.mk +unit-tests/cond-token-number.exp +unit-tests/cond-token-number.mk +unit-tests/cond-token-plain.exp +unit-tests/cond-token-plain.mk +unit-tests/cond-token-string.exp +unit-tests/cond-token-string.mk +unit-tests/cond-token-var.exp +unit-tests/cond-token-var.mk unit-tests/cond1.exp unit-tests/cond1.mk unit-tests/cond2.exp unit-tests/cond2.mk -unit-tests/cond-late.mk -unit-tests/cond-late.exp -unit-tests/cond-short.mk -unit-tests/cond-short.exp +unit-tests/counter.exp +unit-tests/counter.mk +unit-tests/dep-colon.exp +unit-tests/dep-colon.mk +unit-tests/dep-double-colon.exp +unit-tests/dep-double-colon.mk +unit-tests/dep-exclam.exp +unit-tests/dep-exclam.mk +unit-tests/dep-none.exp +unit-tests/dep-none.mk +unit-tests/dep-var.exp +unit-tests/dep-var.mk +unit-tests/dep-wildcards.exp +unit-tests/dep-wildcards.mk +unit-tests/dep.exp +unit-tests/dep.mk +unit-tests/depsrc-exec.exp +unit-tests/depsrc-exec.mk +unit-tests/depsrc-ignore.exp +unit-tests/depsrc-ignore.mk +unit-tests/depsrc-made.exp +unit-tests/depsrc-made.mk +unit-tests/depsrc-make.exp +unit-tests/depsrc-make.mk +unit-tests/depsrc-meta.exp +unit-tests/depsrc-meta.mk +unit-tests/depsrc-nometa.exp +unit-tests/depsrc-nometa.mk +unit-tests/depsrc-nometa_cmp.exp +unit-tests/depsrc-nometa_cmp.mk +unit-tests/depsrc-nopath.exp +unit-tests/depsrc-nopath.mk +unit-tests/depsrc-notmain.exp +unit-tests/depsrc-notmain.mk +unit-tests/depsrc-optional.exp +unit-tests/depsrc-optional.mk +unit-tests/depsrc-phony.exp +unit-tests/depsrc-phony.mk +unit-tests/depsrc-precious.exp +unit-tests/depsrc-precious.mk +unit-tests/depsrc-recursive.exp +unit-tests/depsrc-recursive.mk +unit-tests/depsrc-silent.exp +unit-tests/depsrc-silent.mk +unit-tests/depsrc-use.exp +unit-tests/depsrc-use.mk +unit-tests/depsrc-usebefore.exp +unit-tests/depsrc-usebefore.mk +unit-tests/depsrc-usebefore-double-colon.exp +unit-tests/depsrc-usebefore-double-colon.mk +unit-tests/depsrc-wait.exp +unit-tests/depsrc-wait.mk +unit-tests/depsrc.exp +unit-tests/depsrc.mk +unit-tests/deptgt-begin.exp +unit-tests/deptgt-begin.mk +unit-tests/deptgt-default.exp +unit-tests/deptgt-default.mk +unit-tests/deptgt-delete_on_error.exp +unit-tests/deptgt-delete_on_error.mk +unit-tests/deptgt-end.exp +unit-tests/deptgt-end.mk +unit-tests/deptgt-error.exp +unit-tests/deptgt-error.mk +unit-tests/deptgt-ignore.exp +unit-tests/deptgt-ignore.mk +unit-tests/deptgt-interrupt.exp +unit-tests/deptgt-interrupt.mk +unit-tests/deptgt-main.exp +unit-tests/deptgt-main.mk +unit-tests/deptgt-makeflags.exp +unit-tests/deptgt-makeflags.mk +unit-tests/deptgt-no_parallel.exp +unit-tests/deptgt-no_parallel.mk +unit-tests/deptgt-nopath.exp +unit-tests/deptgt-nopath.mk +unit-tests/deptgt-notparallel.exp +unit-tests/deptgt-notparallel.mk +unit-tests/deptgt-objdir.exp +unit-tests/deptgt-objdir.mk +unit-tests/deptgt-order.exp +unit-tests/deptgt-order.mk +unit-tests/deptgt-path-suffix.exp +unit-tests/deptgt-path-suffix.mk +unit-tests/deptgt-path.exp +unit-tests/deptgt-path.mk +unit-tests/deptgt-phony.exp +unit-tests/deptgt-phony.mk +unit-tests/deptgt-precious.exp +unit-tests/deptgt-precious.mk +unit-tests/deptgt-shell.exp +unit-tests/deptgt-shell.mk +unit-tests/deptgt-silent.exp +unit-tests/deptgt-silent.mk +unit-tests/deptgt-stale.exp +unit-tests/deptgt-stale.mk +unit-tests/deptgt-suffixes.exp +unit-tests/deptgt-suffixes.mk +unit-tests/deptgt.exp +unit-tests/deptgt.mk +unit-tests/dir.exp +unit-tests/dir.mk +unit-tests/dir-expand-path.exp +unit-tests/dir-expand-path.mk +unit-tests/directive-elif.exp +unit-tests/directive-elif.mk +unit-tests/directive-elifdef.exp +unit-tests/directive-elifdef.mk +unit-tests/directive-elifmake.exp +unit-tests/directive-elifmake.mk +unit-tests/directive-elifndef.exp +unit-tests/directive-elifndef.mk +unit-tests/directive-elifnmake.exp +unit-tests/directive-elifnmake.mk +unit-tests/directive-else.exp +unit-tests/directive-else.mk +unit-tests/directive-endif.exp +unit-tests/directive-endif.mk +unit-tests/directive-error.exp +unit-tests/directive-error.mk +unit-tests/directive-export-env.exp +unit-tests/directive-export-env.mk +unit-tests/directive-export-literal.exp +unit-tests/directive-export-literal.mk +unit-tests/directive-export.exp +unit-tests/directive-export.mk +unit-tests/directive-for.exp +unit-tests/directive-for.mk +unit-tests/directive-for-generating-endif.exp +unit-tests/directive-for-generating-endif.mk +unit-tests/directive-if.exp +unit-tests/directive-if.mk +unit-tests/directive-ifdef.exp +unit-tests/directive-ifdef.mk +unit-tests/directive-ifmake.exp +unit-tests/directive-ifmake.mk +unit-tests/directive-ifndef.exp +unit-tests/directive-ifndef.mk +unit-tests/directive-ifnmake.exp +unit-tests/directive-ifnmake.mk +unit-tests/directive-info.exp +unit-tests/directive-info.mk +unit-tests/directive-undef.exp +unit-tests/directive-undef.mk +unit-tests/directive-unexport-env.exp +unit-tests/directive-unexport-env.mk +unit-tests/directive-unexport.exp +unit-tests/directive-unexport.mk +unit-tests/directive-warning.exp +unit-tests/directive-warning.mk +unit-tests/directive.exp +unit-tests/directive.mk +unit-tests/directives.exp +unit-tests/directives.mk unit-tests/dollar.exp unit-tests/dollar.mk unit-tests/doterror.exp unit-tests/doterror.mk unit-tests/dotwait.exp unit-tests/dotwait.mk +unit-tests/envfirst.exp +unit-tests/envfirst.mk unit-tests/error.exp unit-tests/error.mk unit-tests/escape.exp @@ -124,6 +309,8 @@ unit-tests/export-all.exp unit-tests/export-all.mk unit-tests/export-env.exp unit-tests/export-env.mk +unit-tests/export-variants.exp +unit-tests/export-variants.mk unit-tests/export.exp unit-tests/export.mk unit-tests/forloop.exp @@ -138,6 +325,10 @@ unit-tests/include-main.exp unit-tests/include-main.mk unit-tests/include-sub.mk unit-tests/include-subsub.mk +unit-tests/lint.exp +unit-tests/lint.mk +unit-tests/make-exported.exp +unit-tests/make-exported.mk unit-tests/misc.exp unit-tests/misc.mk unit-tests/moderrs.exp @@ -146,12 +337,62 @@ unit-tests/modmatch.exp unit-tests/modmatch.mk unit-tests/modmisc.exp unit-tests/modmisc.mk -unit-tests/modorder.exp -unit-tests/modorder.mk unit-tests/modts.exp unit-tests/modts.mk unit-tests/modword.exp unit-tests/modword.mk +unit-tests/opt-backwards.exp +unit-tests/opt-backwards.mk +unit-tests/opt-chdir.exp +unit-tests/opt-chdir.mk +unit-tests/opt-debug.exp +unit-tests/opt-debug.mk +unit-tests/opt-debug-g1.exp +unit-tests/opt-debug-g1.mk +unit-tests/opt-define.exp +unit-tests/opt-define.mk +unit-tests/opt-env.exp +unit-tests/opt-env.mk +unit-tests/opt-file.exp +unit-tests/opt-file.mk +unit-tests/opt-ignore.exp +unit-tests/opt-ignore.mk +unit-tests/opt-include-dir.exp +unit-tests/opt-include-dir.mk +unit-tests/opt-jobs-internal.exp +unit-tests/opt-jobs-internal.mk +unit-tests/opt-jobs.exp +unit-tests/opt-jobs.mk +unit-tests/opt-keep-going.exp +unit-tests/opt-keep-going.mk +unit-tests/opt-m-include-dir.exp +unit-tests/opt-m-include-dir.mk +unit-tests/opt-no-action-at-all.exp +unit-tests/opt-no-action-at-all.mk +unit-tests/opt-no-action.exp +unit-tests/opt-no-action.mk +unit-tests/opt-query.exp +unit-tests/opt-query.mk +unit-tests/opt-raw.exp +unit-tests/opt-raw.mk +unit-tests/opt-silent.exp +unit-tests/opt-silent.mk +unit-tests/opt-touch.exp +unit-tests/opt-touch.mk +unit-tests/opt-tracefile.exp +unit-tests/opt-tracefile.mk +unit-tests/opt-var-expanded.exp +unit-tests/opt-var-expanded.mk +unit-tests/opt-var-literal.exp +unit-tests/opt-var-literal.mk +unit-tests/opt-warnings-as-errors.exp +unit-tests/opt-warnings-as-errors.mk +unit-tests/opt-where-am-i.exp +unit-tests/opt-where-am-i.mk +unit-tests/opt-x-reduce-exported.exp +unit-tests/opt-x-reduce-exported.mk +unit-tests/opt.exp +unit-tests/opt.mk unit-tests/order.exp unit-tests/order.mk unit-tests/phony-end.exp @@ -162,6 +403,28 @@ unit-tests/posix1.exp unit-tests/posix1.mk unit-tests/qequals.exp unit-tests/qequals.mk +unit-tests/recursive.exp +unit-tests/recursive.mk +unit-tests/sh-dots.exp +unit-tests/sh-dots.mk +unit-tests/sh-jobs-error.exp +unit-tests/sh-jobs-error.mk +unit-tests/sh-jobs.exp +unit-tests/sh-jobs.mk +unit-tests/sh-leading-at.exp +unit-tests/sh-leading-at.mk +unit-tests/sh-leading-hyphen.exp +unit-tests/sh-leading-hyphen.mk +unit-tests/sh-leading-plus.exp +unit-tests/sh-leading-plus.mk +unit-tests/sh-meta-chars.exp +unit-tests/sh-meta-chars.mk +unit-tests/sh-multi-line.exp +unit-tests/sh-multi-line.mk +unit-tests/sh-single-line.exp +unit-tests/sh-single-line.mk +unit-tests/sh.exp +unit-tests/sh.mk unit-tests/suffixes.exp unit-tests/suffixes.mk unit-tests/sunshcmd.exp @@ -174,12 +437,204 @@ unit-tests/unexport-env.exp unit-tests/unexport-env.mk unit-tests/unexport.exp unit-tests/unexport.mk +unit-tests/use-inference.exp +unit-tests/use-inference.mk +unit-tests/var-class-cmdline.exp +unit-tests/var-class-cmdline.mk +unit-tests/var-class-env.exp +unit-tests/var-class-env.mk +unit-tests/var-class-global.exp +unit-tests/var-class-global.mk +unit-tests/var-class-local-legacy.exp +unit-tests/var-class-local-legacy.mk +unit-tests/var-class-local.exp +unit-tests/var-class-local.mk +unit-tests/var-class.exp +unit-tests/var-class.mk +unit-tests/var-op-append.exp +unit-tests/var-op-append.mk +unit-tests/var-op-assign.exp +unit-tests/var-op-assign.mk +unit-tests/var-op-default.exp +unit-tests/var-op-default.mk +unit-tests/var-op-expand.exp +unit-tests/var-op-expand.mk +unit-tests/var-op-shell.exp +unit-tests/var-op-shell.mk +unit-tests/var-op.exp +unit-tests/var-op.mk unit-tests/varcmd.exp unit-tests/varcmd.mk +unit-tests/vardebug.exp +unit-tests/vardebug.mk +unit-tests/varfind.exp +unit-tests/varfind.mk unit-tests/varmisc.exp unit-tests/varmisc.mk +unit-tests/varmod-assign.exp +unit-tests/varmod-assign.mk +unit-tests/varmod-defined.exp +unit-tests/varmod-defined.mk unit-tests/varmod-edge.exp unit-tests/varmod-edge.mk +unit-tests/varmod-exclam-shell.exp +unit-tests/varmod-exclam-shell.mk +unit-tests/varmod-extension.exp +unit-tests/varmod-extension.mk +unit-tests/varmod-gmtime.exp +unit-tests/varmod-gmtime.mk +unit-tests/varmod-hash.exp +unit-tests/varmod-hash.mk +unit-tests/varmod-head.exp +unit-tests/varmod-head.mk +unit-tests/varmod-ifelse.exp +unit-tests/varmod-ifelse.mk +unit-tests/varmod-l-name-to-value.exp +unit-tests/varmod-l-name-to-value.mk +unit-tests/varmod-localtime.exp +unit-tests/varmod-localtime.mk +unit-tests/varmod-loop.exp +unit-tests/varmod-loop.mk +unit-tests/varmod-match-escape.exp +unit-tests/varmod-match-escape.mk +unit-tests/varmod-match.exp +unit-tests/varmod-match.mk +unit-tests/varmod-no-match.exp +unit-tests/varmod-no-match.mk +unit-tests/varmod-order-reverse.exp +unit-tests/varmod-order-reverse.mk +unit-tests/varmod-order-shuffle.exp +unit-tests/varmod-order-shuffle.mk +unit-tests/varmod-order.exp +unit-tests/varmod-order.mk +unit-tests/varmod-path.exp +unit-tests/varmod-path.mk +unit-tests/varmod-quote-dollar.exp +unit-tests/varmod-quote-dollar.mk +unit-tests/varmod-quote.exp +unit-tests/varmod-quote.mk +unit-tests/varmod-range.exp +unit-tests/varmod-range.mk +unit-tests/varmod-remember.exp +unit-tests/varmod-remember.mk +unit-tests/varmod-root.exp +unit-tests/varmod-root.mk +unit-tests/varmod-select-words.exp +unit-tests/varmod-select-words.mk +unit-tests/varmod-shell.exp +unit-tests/varmod-shell.mk +unit-tests/varmod-subst-regex.exp +unit-tests/varmod-subst-regex.mk +unit-tests/varmod-subst.exp +unit-tests/varmod-subst.mk +unit-tests/varmod-sysv.exp +unit-tests/varmod-sysv.mk +unit-tests/varmod-tail.exp +unit-tests/varmod-tail.mk +unit-tests/varmod-to-abs.exp +unit-tests/varmod-to-abs.mk +unit-tests/varmod-to-lower.exp +unit-tests/varmod-to-lower.mk +unit-tests/varmod-to-many-words.exp +unit-tests/varmod-to-many-words.mk +unit-tests/varmod-to-one-word.exp +unit-tests/varmod-to-one-word.mk +unit-tests/varmod-to-separator.exp +unit-tests/varmod-to-separator.mk +unit-tests/varmod-to-upper.exp +unit-tests/varmod-to-upper.mk +unit-tests/varmod-undefined.exp +unit-tests/varmod-undefined.mk +unit-tests/varmod-unique.exp +unit-tests/varmod-unique.mk +unit-tests/varmod.exp +unit-tests/varmod.mk +unit-tests/varname-dollar.exp +unit-tests/varname-dollar.mk +unit-tests/varname-dot-alltargets.exp +unit-tests/varname-dot-alltargets.mk +unit-tests/varname-dot-curdir.exp +unit-tests/varname-dot-curdir.mk +unit-tests/varname-dot-includes.exp +unit-tests/varname-dot-includes.mk +unit-tests/varname-dot-includedfromdir.exp +unit-tests/varname-dot-includedfromdir.mk +unit-tests/varname-dot-includedfromfile.exp +unit-tests/varname-dot-includedfromfile.mk +unit-tests/varname-dot-libs.exp +unit-tests/varname-dot-libs.mk +unit-tests/varname-dot-make-dependfile.exp +unit-tests/varname-dot-make-dependfile.mk +unit-tests/varname-dot-make-expand_variables.exp +unit-tests/varname-dot-make-expand_variables.mk +unit-tests/varname-dot-make-exported.exp +unit-tests/varname-dot-make-exported.mk +unit-tests/varname-dot-make-jobs-prefix.exp +unit-tests/varname-dot-make-jobs-prefix.mk +unit-tests/varname-dot-make-jobs.exp +unit-tests/varname-dot-make-jobs.mk +unit-tests/varname-dot-make-level.exp +unit-tests/varname-dot-make-level.mk +unit-tests/varname-dot-make-makefile_preference.exp +unit-tests/varname-dot-make-makefile_preference.mk +unit-tests/varname-dot-make-makefiles.exp +unit-tests/varname-dot-make-makefiles.mk +unit-tests/varname-dot-make-meta-bailiwick.exp +unit-tests/varname-dot-make-meta-bailiwick.mk +unit-tests/varname-dot-make-meta-created.exp +unit-tests/varname-dot-make-meta-created.mk +unit-tests/varname-dot-make-meta-files.exp +unit-tests/varname-dot-make-meta-files.mk +unit-tests/varname-dot-make-meta-ignore_filter.exp +unit-tests/varname-dot-make-meta-ignore_filter.mk +unit-tests/varname-dot-make-meta-ignore_paths.exp +unit-tests/varname-dot-make-meta-ignore_paths.mk +unit-tests/varname-dot-make-meta-ignore_patterns.exp +unit-tests/varname-dot-make-meta-ignore_patterns.mk +unit-tests/varname-dot-make-meta-prefix.exp +unit-tests/varname-dot-make-meta-prefix.mk +unit-tests/varname-dot-make-mode.exp +unit-tests/varname-dot-make-mode.mk +unit-tests/varname-dot-make-path_filemon.exp +unit-tests/varname-dot-make-path_filemon.mk +unit-tests/varname-dot-make-pid.exp +unit-tests/varname-dot-make-pid.mk +unit-tests/varname-dot-make-ppid.exp +unit-tests/varname-dot-make-ppid.mk +unit-tests/varname-dot-make-save_dollars.exp +unit-tests/varname-dot-make-save_dollars.mk +unit-tests/varname-dot-makeoverrides.exp +unit-tests/varname-dot-makeoverrides.mk +unit-tests/varname-dot-newline.exp +unit-tests/varname-dot-newline.mk +unit-tests/varname-dot-objdir.exp +unit-tests/varname-dot-objdir.mk +unit-tests/varname-dot-parsedir.exp +unit-tests/varname-dot-parsedir.mk +unit-tests/varname-dot-parsefile.exp +unit-tests/varname-dot-parsefile.mk +unit-tests/varname-dot-path.exp +unit-tests/varname-dot-path.mk +unit-tests/varname-dot-shell.exp +unit-tests/varname-dot-shell.mk +unit-tests/varname-dot-targets.exp +unit-tests/varname-dot-targets.mk +unit-tests/varname-empty.exp +unit-tests/varname-empty.mk +unit-tests/varname-make.exp +unit-tests/varname-make.mk +unit-tests/varname-make_print_var_on_error.exp +unit-tests/varname-make_print_var_on_error.mk +unit-tests/varname-makeflags.exp +unit-tests/varname-makeflags.mk +unit-tests/varname-pwd.exp +unit-tests/varname-pwd.mk +unit-tests/varname-vpath.exp +unit-tests/varname-vpath.mk +unit-tests/varname.exp +unit-tests/varname.mk +unit-tests/varparse-dynamic.exp +unit-tests/varparse-dynamic.mk unit-tests/varquote.exp unit-tests/varquote.mk unit-tests/varshell.exp @@ -3,6 +3,7 @@ original contributors or assignees. Including: Copyright (c) 1993-2020, Simon J Gerraty + Copyright (c) 2020, Roland Illig <rillig@NetBSD.org> Copyright (c) 2009-2016, Juniper Networks, Inc. Copyright (c) 2009, John Birrell. Copyright (c) 1997-2020 The NetBSD Foundation, Inc. @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.107 2020/06/07 21:18:46 sjg Exp $ +# $Id: Makefile,v 1.112 2020/08/28 16:26:17 sjg Exp $ PROG= bmake @@ -8,9 +8,11 @@ SRCS= \ compat.c \ cond.c \ dir.c \ + enum.c \ for.c \ hash.c \ job.c \ + lst.c \ main.c \ make.c \ make_malloc.c \ @@ -25,36 +27,6 @@ SRCS= \ util.c \ var.c -# from lst.lib/ -SRCS+= \ - lstAppend.c \ - lstAtEnd.c \ - lstAtFront.c \ - lstClose.c \ - lstConcat.c \ - lstDatum.c \ - lstDeQueue.c \ - lstDestroy.c \ - lstDupl.c \ - lstEnQueue.c \ - lstFind.c \ - lstFindFrom.c \ - lstFirst.c \ - lstForEach.c \ - lstForEachFrom.c \ - lstInit.c \ - lstInsert.c \ - lstIsAtEnd.c \ - lstIsEmpty.c \ - lstLast.c \ - lstMember.c \ - lstNext.c \ - lstOpen.c \ - lstPrev.c \ - lstRemove.c \ - lstReplace.c \ - lstSucc.c - .-include "VERSION" .-include "Makefile.inc" @@ -97,7 +69,6 @@ COPTS.filemon_dev.c += -DHAVE_FILEMON_H -I${FILEMON_H:H} .endif # USE_FILEMON .PATH: ${srcdir} -.PATH: ${srcdir}/lst.lib .if make(obj) || make(clean) SUBDIR+= unit-tests @@ -109,7 +80,7 @@ SUBDIR+= unit-tests # list of OS's which are derrived from BSD4.4 BSD44_LIST= NetBSD FreeBSD OpenBSD DragonFly MirBSD Bitrig # we are... -OS!= uname -s +OS := ${.MAKE.OS:U${uname -s:L:sh}} # are we 4.4BSD ? isBSD44:=${BSD44_LIST:M${OS}} @@ -237,5 +208,8 @@ install-mk: # end-delete2 # A simple unit-test driver to help catch regressions +TEST_MAKE ?= ${.OBJDIR}/${PROG:T} accept test: - cd ${.CURDIR}/unit-tests && MAKEFLAGS= ${.MAKE} -r -m / TEST_MAKE=${TEST_MAKE:U${.OBJDIR}/${PROG:T}} ${.TARGET} + cd ${.CURDIR}/unit-tests && \ + MAKEFLAGS= ${TEST_MAKE} -r -m / ${.TARGET} ${TESTS:DTESTS=${TESTS:Q}} + @@ -1,2 +1,2 @@ # keep this compatible with sh and make -_MAKE_VERSION=20200710 +_MAKE_VERSION=20200902 @@ -1,4 +1,4 @@ -/* $NetBSD: arch.c,v 1.73 2020/07/03 08:02:55 rillig Exp $ */ +/* $NetBSD: arch.c,v 1.107 2020/08/30 11:15:05 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -69,14 +69,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: arch.c,v 1.73 2020/07/03 08:02:55 rillig Exp $"; +static char rcsid[] = "$NetBSD: arch.c,v 1.107 2020/08/30 11:15:05 rillig Exp $"; #else #include <sys/cdefs.h> #ifndef lint #if 0 static char sccsid[] = "@(#)arch.c 8.2 (Berkeley) 1/2/94"; #else -__RCSID("$NetBSD: arch.c,v 1.73 2020/07/03 08:02:55 rillig Exp $"); +__RCSID("$NetBSD: arch.c,v 1.107 2020/08/30 11:15:05 rillig Exp $"); #endif #endif /* not lint */ #endif @@ -94,7 +94,7 @@ __RCSID("$NetBSD: arch.c,v 1.73 2020/07/03 08:02:55 rillig Exp $"); * The interface to this module is: * Arch_ParseArchive Given an archive specification, return a list * of GNode's, one for each member in the spec. - * FAILURE is returned if the specification is + * FALSE is returned if the specification is * invalid for some reason. * * Arch_Touch Alter the modification time of the archive @@ -184,12 +184,9 @@ typedef struct Arch { size_t fnamesize; /* Size of the string table */ } Arch; -static int ArchFindArchive(const void *, const void *); -#ifdef CLEANUP -static void ArchFree(void *); -#endif -static struct ar_hdr *ArchStatMember(char *, char *, Boolean); -static FILE *ArchFindMember(char *, char *, struct ar_hdr *, const char *); +static struct ar_hdr *ArchStatMember(const char *, const char *, Boolean); +static FILE *ArchFindMember(const char *, const char *, + struct ar_hdr *, const char *); #if defined(__svr4__) || defined(__SVR4) || defined(__ELF__) #define SVR4ARCHIVES static int ArchSVR4Entry(Arch *, char *, size_t, FILE *); @@ -225,19 +222,6 @@ static int ArchSVR4Entry(Arch *, char *, size_t, FILE *); #define AR_MAX_NAME_LEN (sizeof(arh.AR_NAME)-1) #ifdef CLEANUP -/*- - *----------------------------------------------------------------------- - * ArchFree -- - * Free memory used by an archive - * - * Results: - * None. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ static void ArchFree(void *ap) { @@ -272,23 +256,18 @@ ArchFree(void *ap) * ctxt Context in which to expand variables * * Results: - * SUCCESS if it was a valid specification. The linePtr is updated + * TRUE if it was a valid specification. The linePtr is updated * to point to the first non-space after the archive spec. The * nodes for the members are placed on the given list. - * - * Side Effects: - * Some nodes may be created. The given list is extended. - * *----------------------------------------------------------------------- */ -ReturnStatus +Boolean Arch_ParseArchive(char **linePtr, Lst nodeLst, GNode *ctxt) { char *cp; /* Pointer into line */ GNode *gn; /* New node */ char *libName; /* Library-part of specification */ char *memName; /* Member-part of specification */ - char *nameBuf; /* temporary place for node name */ char saveChar; /* Ending delimiter of member-name */ Boolean subLibName; /* TRUE if libName should have/had * variable substitution performed on it */ @@ -304,26 +283,25 @@ Arch_ParseArchive(char **linePtr, Lst nodeLst, GNode *ctxt) * so we can safely advance beyond it... */ int length; - void *freeIt; - char *result; - - result = Var_Parse(cp, ctxt, VARF_UNDEFERR|VARF_WANTRES, - &length, &freeIt); - free(freeIt); - - if (result == var_Error) { - return FAILURE; - } else { - subLibName = TRUE; - } - - cp += length-1; + void *result_freeIt; + const char *result; + Boolean isError; + + result = Var_Parse(cp, ctxt, VARE_UNDEFERR|VARE_WANTRES, + &length, &result_freeIt); + isError = result == var_Error; + free(result_freeIt); + if (isError) + return FALSE; + + subLibName = TRUE; + cp += length - 1; } } *cp++ = '\0'; if (subLibName) { - libName = Var_Subst(NULL, libName, ctxt, VARF_UNDEFERR|VARF_WANTRES); + libName = Var_Subst(libName, ctxt, VARE_UNDEFERR|VARE_WANTRES); } @@ -347,18 +325,18 @@ Arch_ParseArchive(char **linePtr, Lst nodeLst, GNode *ctxt) */ int length; void *freeIt; - char *result; + const char *result; + Boolean isError; - result = Var_Parse(cp, ctxt, VARF_UNDEFERR|VARF_WANTRES, + result = Var_Parse(cp, ctxt, VARE_UNDEFERR|VARE_WANTRES, &length, &freeIt); + isError = result == var_Error; free(freeIt); - if (result == var_Error) { - return FAILURE; - } else { - doSubst = TRUE; - } + if (isError) + return FALSE; + doSubst = TRUE; cp += length; } else { cp++; @@ -372,7 +350,7 @@ Arch_ParseArchive(char **linePtr, Lst nodeLst, GNode *ctxt) */ if (*cp == '\0') { printf("No closing parenthesis in archive specification\n"); - return FAILURE; + return FALSE; } /* @@ -401,20 +379,15 @@ Arch_ParseArchive(char **linePtr, Lst nodeLst, GNode *ctxt) char *buf; char *sacrifice; char *oldMemName = memName; - size_t sz; - memName = Var_Subst(NULL, memName, ctxt, - VARF_UNDEFERR|VARF_WANTRES); + memName = Var_Subst(memName, ctxt, VARE_UNDEFERR | VARE_WANTRES); /* * Now form an archive spec and recurse to deal with nested * variables and multi-word variable values.... The results * are just placed at the end of the nodeLst we're returning. */ - sz = strlen(memName)+strlen(libName)+3; - buf = sacrifice = bmake_malloc(sz); - - snprintf(buf, sz, "%s(%s)", libName, memName); + buf = sacrifice = str_concat4(libName, "(", memName, ")"); if (strchr(memName, '$') && strcmp(memName, oldMemName) == 0) { /* @@ -426,42 +399,43 @@ Arch_ParseArchive(char **linePtr, Lst nodeLst, GNode *ctxt) if (gn == NULL) { free(buf); - return FAILURE; + return FALSE; } else { gn->type |= OP_ARCHV; - (void)Lst_AtEnd(nodeLst, gn); + Lst_Append(nodeLst, gn); } - } else if (Arch_ParseArchive(&sacrifice, nodeLst, ctxt)!=SUCCESS) { + } else if (!Arch_ParseArchive(&sacrifice, nodeLst, ctxt)) { /* - * Error in nested call -- free buffer and return FAILURE + * Error in nested call -- free buffer and return FALSE * ourselves. */ free(buf); - return FAILURE; + return FALSE; } /* * Free buffer and continue with our work. */ free(buf); } else if (Dir_HasWildcards(memName)) { - Lst members = Lst_Init(FALSE); - char *member; - size_t sz = MAXPATHLEN, nsz; - nameBuf = bmake_malloc(sz); + Lst members = Lst_Init(); + Buffer nameBuf; + Buf_Init(&nameBuf, 0); Dir_Expand(memName, dirSearchPath, members); while (!Lst_IsEmpty(members)) { - member = (char *)Lst_DeQueue(members); - nsz = strlen(libName) + strlen(member) + 3; - if (sz > nsz) - nameBuf = bmake_realloc(nameBuf, sz = nsz * 2); + char *member = Lst_Dequeue(members); - snprintf(nameBuf, sz, "%s(%s)", libName, member); + Buf_Empty(&nameBuf); + Buf_AddStr(&nameBuf, libName); + Buf_AddStr(&nameBuf, "("); + Buf_AddStr(&nameBuf, member); + Buf_AddStr(&nameBuf, ")"); free(member); - gn = Targ_FindNode(nameBuf, TARG_CREATE); + + gn = Targ_FindNode(Buf_GetAll(&nameBuf, NULL), TARG_CREATE); if (gn == NULL) { - free(nameBuf); - return FAILURE; + Buf_Destroy(&nameBuf, TRUE); + return FALSE; } else { /* * We've found the node, but have to make sure the rest of @@ -471,19 +445,24 @@ Arch_ParseArchive(char **linePtr, Lst nodeLst, GNode *ctxt) * end of the provided list. */ gn->type |= OP_ARCHV; - (void)Lst_AtEnd(nodeLst, gn); + Lst_Append(nodeLst, gn); } } - Lst_Destroy(members, NULL); - free(nameBuf); + Lst_Free(members); + Buf_Destroy(&nameBuf, TRUE); } else { - size_t sz = strlen(libName) + strlen(memName) + 3; - nameBuf = bmake_malloc(sz); - snprintf(nameBuf, sz, "%s(%s)", libName, memName); - gn = Targ_FindNode(nameBuf, TARG_CREATE); - free(nameBuf); + Buffer nameBuf; + + Buf_Init(&nameBuf, 0); + Buf_AddStr(&nameBuf, libName); + Buf_AddStr(&nameBuf, "("); + Buf_AddStr(&nameBuf, memName); + Buf_AddStr(&nameBuf, ")"); + + gn = Targ_FindNode(Buf_GetAll(&nameBuf, NULL), TARG_CREATE); + Buf_Destroy(&nameBuf, TRUE); if (gn == NULL) { - return FAILURE; + return FALSE; } else { /* * We've found the node, but have to make sure the rest of the @@ -493,7 +472,7 @@ Arch_ParseArchive(char **linePtr, Lst nodeLst, GNode *ctxt) * provided list. */ gn->type |= OP_ARCHV; - (void)Lst_AtEnd(nodeLst, gn); + Lst_Append(nodeLst, gn); } } if (doSubst) { @@ -520,31 +499,15 @@ Arch_ParseArchive(char **linePtr, Lst nodeLst, GNode *ctxt) } while (*cp != '\0' && isspace ((unsigned char)*cp)); *linePtr = cp; - return SUCCESS; + return TRUE; } -/*- - *----------------------------------------------------------------------- - * ArchFindArchive -- - * See if the given archive is the one we are looking for. Called - * From ArchStatMember and ArchFindMember via Lst_Find. - * - * Input: - * ar Current list element - * archName Name we want - * - * Results: - * 0 if it is, non-zero if it isn't. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -static int -ArchFindArchive(const void *ar, const void *archName) +/* See if the given archive is the one we are looking for. + * Called via Lst_Find. */ +static Boolean +ArchFindArchive(const void *ar, const void *desiredName) { - return strcmp(archName, ((const Arch *)ar)->name); + return strcmp(((const Arch *)ar)->name, desiredName) == 0; } /*- @@ -565,24 +528,20 @@ ArchFindArchive(const void *ar, const void *archName) * archive members. This is mostly because we have no assurances that * The archive will remain constant after we read all the headers, so * there's not much point in remembering the position... - * - * Side Effects: - * *----------------------------------------------------------------------- */ static struct ar_hdr * -ArchStatMember(char *archive, char *member, Boolean hash) +ArchStatMember(const char *archive, const char *member, Boolean hash) { FILE * arch; /* Stream to archive */ - int size; /* Size of archive member */ - char *cp; /* Useful character pointer */ + size_t size; /* Size of archive member */ char magic[SARMAG]; LstNode ln; /* Lst member containing archive descriptor */ Arch *ar; /* Archive descriptor */ Hash_Entry *he; /* Entry containing member's description */ struct ar_hdr arh; /* archive-member header for reading archive */ char memName[MAXPATHLEN+1]; - /* Current member name while hashing. */ + /* Current member name while hashing. */ /* * Because of space constraints and similar things, files are archived @@ -590,14 +549,14 @@ ArchStatMember(char *archive, char *member, Boolean hash) * to point 'member' to the final component, if there is one, to make * the comparisons easier... */ - cp = strrchr(member, '/'); - if (cp != NULL) { - member = cp + 1; + const char *base = strrchr(member, '/'); + if (base != NULL) { + member = base + 1; } - ln = Lst_Find(archives, archive, ArchFindArchive); + ln = Lst_Find(archives, ArchFindArchive, archive); if (ln != NULL) { - ar = (Arch *)Lst_Datum(ln); + ar = LstNode_Datum(ln); he = Hash_FindEntry(&ar->members, member); @@ -610,8 +569,7 @@ ArchStatMember(char *archive, char *member, Boolean hash) if (len > AR_MAX_NAME_LEN) { len = AR_MAX_NAME_LEN; - strncpy(copy, member, AR_MAX_NAME_LEN); - copy[AR_MAX_NAME_LEN] = '\0'; + snprintf(copy, sizeof copy, "%s", member); } if ((he = Hash_FindEntry(&ar->members, copy)) != NULL) return (struct ar_hdr *)Hash_GetValue(he); @@ -653,7 +611,7 @@ ArchStatMember(char *archive, char *member, Boolean hash) * can handle... */ if ((fread(magic, SARMAG, 1, arch) != 1) || - (strncmp(magic, ARMAG, SARMAG) != 0)) { + (strncmp(magic, ARMAG, SARMAG) != 0)) { fclose(arch); return NULL; } @@ -673,6 +631,8 @@ ArchStatMember(char *archive, char *member, Boolean hash) */ goto badarch; } else { + char *nameend; + /* * We need to advance the stream's pointer to the start of the * next header. Files are padded with newlines to an even-byte @@ -680,13 +640,14 @@ ArchStatMember(char *archive, char *member, Boolean hash) * 'size' field of the header and round it up during the seek. */ arh.AR_SIZE[sizeof(arh.AR_SIZE)-1] = '\0'; - size = (int)strtol(arh.AR_SIZE, NULL, 10); + size = (size_t)strtol(arh.ar_size, NULL, 10); memcpy(memName, arh.AR_NAME, sizeof(arh.AR_NAME)); - for (cp = &memName[AR_MAX_NAME_LEN]; *cp == ' '; cp--) { - continue; + nameend = memName + AR_MAX_NAME_LEN; + while (*nameend == ' ') { + nameend--; } - cp[1] = '\0'; + nameend[1] = '\0'; #ifdef SVR4ARCHIVES /* @@ -706,8 +667,8 @@ ArchStatMember(char *archive, char *member, Boolean hash) } } else { - if (cp[0] == '/') - cp[0] = '\0'; + if (nameend[0] == '/') + nameend[0] = '\0'; } #endif @@ -719,11 +680,11 @@ ArchStatMember(char *archive, char *member, Boolean hash) if (strncmp(memName, AR_EFMT1, sizeof(AR_EFMT1) - 1) == 0 && isdigit((unsigned char)memName[sizeof(AR_EFMT1) - 1])) { - unsigned int elen = atoi(&memName[sizeof(AR_EFMT1)-1]); + int elen = atoi(&memName[sizeof(AR_EFMT1)-1]); - if (elen > MAXPATHLEN) + if ((unsigned int)elen > MAXPATHLEN) goto badarch; - if (fread(memName, elen, 1, arch) != 1) + if (fread(memName, (size_t)elen, 1, arch) != 1) goto badarch; memName[elen] = '\0'; if (fseek(arch, -elen, SEEK_CUR) != 0) @@ -738,13 +699,13 @@ ArchStatMember(char *archive, char *member, Boolean hash) Hash_SetValue(he, bmake_malloc(sizeof(struct ar_hdr))); memcpy(Hash_GetValue(he), &arh, sizeof(struct ar_hdr)); } - if (fseek(arch, (size + 1) & ~1, SEEK_CUR) != 0) + if (fseek(arch, ((long)size + 1) & ~1, SEEK_CUR) != 0) goto badarch; } fclose(arch); - (void)Lst_AtEnd(archives, ar); + Lst_Append(archives, ar); /* * Now that the archive has been read and cached, we can look into @@ -774,17 +735,14 @@ badarch: * If it is "//", then load the table of filenames * If it is "/<offset>", then try to substitute the long file name * from offset of a table previously read. + * If a table is read, the file pointer is moved to the next archive + * member. * * Results: * -1: Bad data in archive * 0: A table was loaded from the file * 1: Name was successfully substituted from table * 2: Name was not successfully substituted from table - * - * Side Effects: - * If a table is read, the file pointer is moved to the next archive - * member - * *----------------------------------------------------------------------- */ static int @@ -834,7 +792,7 @@ ArchSVR4Entry(Arch *ar, char *name, size_t size, FILE *arch) } if (DEBUG(ARCH)) { fprintf(debug_file, "Found svr4 archive name table with %lu entries\n", - (unsigned long)entry); + (unsigned long)entry); } return 0; } @@ -861,8 +819,7 @@ ArchSVR4Entry(Arch *ar, char *name, size_t size, FILE *arch) fprintf(debug_file, "Replaced %s with %s\n", name, &ar->fnametab[entry]); } - (void)strncpy(name, &ar->fnametab[entry], MAXPATHLEN); - name[MAXPATHLEN] = '\0'; + snprintf(name, MAXPATHLEN + 1, "%s", &ar->fnametab[entry]); return 1; } #endif @@ -874,6 +831,7 @@ ArchSVR4Entry(Arch *ar, char *name, size_t size, FILE *arch) * Locate a member of an archive, given the path of the archive and * the path of the desired member. If the archive is to be modified, * the mode should be "r+", if not, it should be "r". + * The passed struct ar_hdr structure is filled in. * * Input: * archive Path to the archive @@ -886,21 +844,17 @@ ArchSVR4Entry(Arch *ar, char *name, size_t size, FILE *arch) * An FILE *, opened for reading and writing, positioned at the * start of the member's struct ar_hdr, or NULL if the member was * nonexistent. The current struct ar_hdr for member. - * - * Side Effects: - * The passed struct ar_hdr structure is filled in. - * *----------------------------------------------------------------------- */ static FILE * -ArchFindMember(char *archive, char *member, struct ar_hdr *arhPtr, +ArchFindMember(const char *archive, const char *member, struct ar_hdr *arhPtr, const char *mode) { FILE * arch; /* Stream to archive */ int size; /* Size of archive member */ - char *cp; /* Useful character pointer */ char magic[SARMAG]; size_t len, tlen; + const char * base; arch = fopen(archive, mode); if (arch == NULL) { @@ -912,7 +866,7 @@ ArchFindMember(char *archive, char *member, struct ar_hdr *arhPtr, * can handle... */ if ((fread(magic, SARMAG, 1, arch) != 1) || - (strncmp(magic, ARMAG, SARMAG) != 0)) { + (strncmp(magic, ARMAG, SARMAG) != 0)) { fclose(arch); return NULL; } @@ -923,9 +877,9 @@ ArchFindMember(char *archive, char *member, struct ar_hdr *arhPtr, * to point 'member' to the final component, if there is one, to make * the comparisons easier... */ - cp = strrchr(member, '/'); - if (cp != NULL) { - member = cp + 1; + base = strrchr(member, '/'); + if (base != NULL) { + member = base + 1; } len = tlen = strlen(member); if (len > sizeof(arhPtr->AR_NAME)) { @@ -958,7 +912,7 @@ ArchFindMember(char *archive, char *member, struct ar_hdr *arhPtr, * the file at the actual member, rather than its header, but * not here... */ - if (fseek(arch, -sizeof(struct ar_hdr), SEEK_CUR) != 0) { + if (fseek(arch, -(long)sizeof(struct ar_hdr), SEEK_CUR) != 0) { fclose(arch); return NULL; } @@ -974,14 +928,14 @@ ArchFindMember(char *archive, char *member, struct ar_hdr *arhPtr, sizeof(AR_EFMT1) - 1) == 0 && isdigit((unsigned char)arhPtr->AR_NAME[sizeof(AR_EFMT1) - 1])) { - unsigned int elen = atoi(&arhPtr->AR_NAME[sizeof(AR_EFMT1)-1]); + int elen = atoi(&arhPtr->AR_NAME[sizeof(AR_EFMT1)-1]); char ename[MAXPATHLEN + 1]; - if (elen > MAXPATHLEN) { + if ((unsigned int)elen > MAXPATHLEN) { fclose(arch); return NULL; } - if (fread(ename, elen, 1, arch) != 1) { + if (fread(ename, (size_t)elen, 1, arch) != 1) { fclose(arch); return NULL; } @@ -991,7 +945,7 @@ ArchFindMember(char *archive, char *member, struct ar_hdr *arhPtr, } if (strncmp(ename, member, len) == 0) { /* Found as extended name */ - if (fseek(arch, -sizeof(struct ar_hdr) - elen, + if (fseek(arch, -(long)sizeof(struct ar_hdr) - elen, SEEK_CUR) != 0) { fclose(arch); return NULL; @@ -1035,18 +989,15 @@ skip: *----------------------------------------------------------------------- * Arch_Touch -- * Touch a member of an archive. + * The modification time of the entire archive is also changed. + * For a library, this could necessitate the re-ranlib'ing of the + * whole thing. * * Input: * gn Node of member to touch * * Results: * The 'time' field of the member's header is updated. - * - * Side Effects: - * The modification time of the entire archive is also changed. - * For a library, this could necessitate the re-ranlib'ing of the - * whole thing. - * *----------------------------------------------------------------------- */ void @@ -1060,8 +1011,8 @@ Arch_Touch(GNode *gn) Var_Value(MEMBER, gn, &p2), &arh, "r+"); - free(p1); - free(p2); + bmake_free(p1); + bmake_free(p2); snprintf(arh.AR_DATE, sizeof(arh.AR_DATE), "%-12ld", (long) now); @@ -1071,37 +1022,24 @@ Arch_Touch(GNode *gn) } } -/*- - *----------------------------------------------------------------------- - * Arch_TouchLib -- - * Given a node which represents a library, touch the thing, making - * sure that the table of contents also is touched. +/* Given a node which represents a library, touch the thing, making sure that + * the table of contents also is touched. + * + * Both the modification time of the library and of the RANLIBMAG member are + * set to 'now'. * * Input: * gn The node of the library to touch - * - * Results: - * None. - * - * Side Effects: - * Both the modification time of the library and of the RANLIBMAG - * member are set to 'now'. - * - *----------------------------------------------------------------------- */ void -#if !defined(RANLIBMAG) -Arch_TouchLib(GNode *gn MAKE_ATTR_UNUSED) -#else Arch_TouchLib(GNode *gn) -#endif { #ifdef RANLIBMAG FILE * arch; /* Stream open to archive */ struct ar_hdr arh; /* Header describing table of contents */ struct utimbuf times; /* Times for utime() call */ - arch = ArchFindMember(gn->path, UNCONST(RANLIBMAG), &arh, "r+"); + arch = ArchFindMember(gn->path, RANLIBMAG, &arh, "r+"); snprintf(arh.AR_DATE, sizeof(arh.AR_DATE), "%-12ld", (long) now); if (arch != NULL) { @@ -1111,25 +1049,16 @@ Arch_TouchLib(GNode *gn) times.actime = times.modtime = now; utime(gn->path, ×); } +#else + (void)gn; #endif } -/*- - *----------------------------------------------------------------------- - * Arch_MTime -- - * Return the modification time of a member of an archive. +/* Return the modification time of a member of an archive. The mtime field + * of the given node is filled in with the value returned by the function. * * Input: * gn Node describing archive member - * - * Results: - * The modification time(seconds). - * - * Side Effects: - * The mtime field of the given node is filled in with the value - * returned by the function. - * - *----------------------------------------------------------------------- */ time_t Arch_MTime(GNode *gn) @@ -1142,8 +1071,8 @@ Arch_MTime(GNode *gn) Var_Value(MEMBER, gn, &p2), TRUE); - free(p1); - free(p2); + bmake_free(p1); + bmake_free(p2); if (arhPtr != NULL) { modTime = (time_t)strtol(arhPtr->AR_DATE, NULL, 10); @@ -1155,34 +1084,17 @@ Arch_MTime(GNode *gn) return modTime; } -/*- - *----------------------------------------------------------------------- - * Arch_MemMTime -- - * Given a non-existent archive member's node, get its modification - * time from its archived form, if it exists. - * - * Results: - * The modification time. - * - * Side Effects: - * The mtime field is filled in. - * - *----------------------------------------------------------------------- - */ +/* Given a non-existent archive member's node, get its modification time from + * its archived form, if it exists. gn->mtime is filled in as well. */ time_t Arch_MemMTime(GNode *gn) { LstNode ln; GNode *pgn; - char *nameStart, - *nameEnd; - if (Lst_Open(gn->parents) != SUCCESS) { - gn->mtime = 0; - return 0; - } + Lst_Open(gn->parents); while ((ln = Lst_Next(gn->parents)) != NULL) { - pgn = (GNode *)Lst_Datum(ln); + pgn = LstNode_Datum(ln); if (pgn->type & OP_ARCHV) { /* @@ -1192,12 +1104,13 @@ Arch_MemMTime(GNode *gn) * child. We keep searching its parents in case some other * parent requires this child to exist... */ - nameStart = strchr(pgn->name, '(') + 1; - nameEnd = strchr(nameStart, ')'); + const char *nameStart = strchr(pgn->name, '(') + 1; + const char *nameEnd = strchr(nameStart, ')'); + size_t nameLen = (size_t)(nameEnd - nameStart); if ((pgn->flags & REMAKE) && - strncmp(nameStart, gn->name, nameEnd - nameStart) == 0) { - gn->mtime = Arch_MTime(pgn); + strncmp(nameStart, gn->name, nameLen) == 0) { + gn->mtime = Arch_MTime(pgn); } } else if (pgn->flags & REMAKE) { /* @@ -1214,29 +1127,20 @@ Arch_MemMTime(GNode *gn) return gn->mtime; } -/*- - *----------------------------------------------------------------------- - * Arch_FindLib -- - * Search for a library along the given search path. +/* Search for a library along the given search path. + * + * The node's 'path' field is set to the found path (including the + * actual file name, not -l...). If the system can handle the -L + * flag when linking (or we cannot find the library), we assume that + * the user has placed the .LIBS variable in the final linking + * command (or the linker will know where to find it) and set the + * TARGET variable for this node to be the node's name. Otherwise, + * we set the TARGET variable to be the full path of the library, + * as returned by Dir_FindFile. * * Input: * gn Node of library to find * path Search path - * - * Results: - * None. - * - * Side Effects: - * The node's 'path' field is set to the found path (including the - * actual file name, not -l...). If the system can handle the -L - * flag when linking (or we cannot find the library), we assume that - * the user has placed the .LIBRARIES variable in the final linking - * command (or the linker will know where to find it) and set the - * TARGET variable for this node to be the node's name. Otherwise, - * we set the TARGET variable to be the full path of the library, - * as returned by Dir_FindFile. - * - *----------------------------------------------------------------------- */ void Arch_FindLib(GNode *gn, Lst path) @@ -1258,44 +1162,38 @@ Arch_FindLib(GNode *gn, Lst path) #endif /* LIBRARIES */ } -/*- - *----------------------------------------------------------------------- - * Arch_LibOODate -- - * Decide if a node with the OP_LIB attribute is out-of-date. Called - * from Make_OODate to make its life easier. - * - * There are several ways for a library to be out-of-date that are - * not available to ordinary files. In addition, there are ways - * that are open to regular files that are not available to - * libraries. A library that is only used as a source is never - * considered out-of-date by itself. This does not preclude the - * library's modification time from making its parent be out-of-date. - * A library will be considered out-of-date for any of these reasons, - * given that it is a target on a dependency line somewhere: - * Its modification time is less than that of one of its - * sources (gn->mtime < gn->cmgn->mtime). - * Its modification time is greater than the time at which the - * make began (i.e. it's been modified in the course - * of the make, probably by archiving). - * The modification time of one of its sources is greater than - * the one of its RANLIBMAG member (i.e. its table of contents - * is out-of-date). We don't compare of the archive time - * vs. TOC time because they can be too close. In my - * opinion we should not bother with the TOC at all since - * this is used by 'ar' rules that affect the data contents - * of the archive, not by ranlib rules, which affect the - * TOC. +/* Decide if a node with the OP_LIB attribute is out-of-date. Called from + * Make_OODate to make its life easier. + * The library will be hashed if it hasn't been already. + * + * There are several ways for a library to be out-of-date that are + * not available to ordinary files. In addition, there are ways + * that are open to regular files that are not available to + * libraries. A library that is only used as a source is never + * considered out-of-date by itself. This does not preclude the + * library's modification time from making its parent be out-of-date. + * A library will be considered out-of-date for any of these reasons, + * given that it is a target on a dependency line somewhere: + * + * Its modification time is less than that of one of its sources + * (gn->mtime < gn->cmgn->mtime). + * + * Its modification time is greater than the time at which the make + * began (i.e. it's been modified in the course of the make, probably + * by archiving). + * + * The modification time of one of its sources is greater than the one + * of its RANLIBMAG member (i.e. its table of contents is out-of-date). + * We don't compare of the archive time vs. TOC time because they can be + * too close. In my opinion we should not bother with the TOC at all + * since this is used by 'ar' rules that affect the data contents of the + * archive, not by ranlib rules, which affect the TOC. * * Input: * gn The library's graph node * * Results: * TRUE if the library is out-of-date. FALSE otherwise. - * - * Side Effects: - * The library will be hashed if it hasn't been already. - * - *----------------------------------------------------------------------- */ Boolean Arch_LibOODate(GNode *gn) @@ -1315,7 +1213,7 @@ Arch_LibOODate(GNode *gn) struct ar_hdr *arhPtr; /* Header for __.SYMDEF */ int modTimeTOC; /* The table-of-contents's mod time */ - arhPtr = ArchStatMember(gn->path, UNCONST(RANLIBMAG), FALSE); + arhPtr = ArchStatMember(gn->path, RANLIBMAG, FALSE); if (arhPtr != NULL) { modTimeTOC = (int)strtol(arhPtr->AR_DATE, NULL, 10); @@ -1340,40 +1238,14 @@ Arch_LibOODate(GNode *gn) return oodate; } -/*- - *----------------------------------------------------------------------- - * Arch_Init -- - * Initialize things for this module. - * - * Results: - * None. - * - * Side Effects: - * The 'archives' list is initialized. - * - *----------------------------------------------------------------------- - */ +/* Initialize things for this module. */ void Arch_Init(void) { - archives = Lst_Init(FALSE); + archives = Lst_Init(); } - - -/*- - *----------------------------------------------------------------------- - * Arch_End -- - * Cleanup things for this module. - * - * Results: - * None. - * - * Side Effects: - * The 'archives' list is freed - * - *----------------------------------------------------------------------- - */ +/* Clean up things for this module. */ void Arch_End(void) { @@ -1382,35 +1254,22 @@ Arch_End(void) #endif } -/*- - *----------------------------------------------------------------------- - * Arch_IsLib -- - * Check if the node is a library - * - * Results: - * True or False. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -int +Boolean Arch_IsLib(GNode *gn) { static const char armag[] = "!<arch>\n"; - char buf[sizeof(armag)-1]; + char buf[sizeof armag - 1]; int fd; if ((fd = open(gn->path, O_RDONLY)) == -1) return FALSE; - if (read(fd, buf, sizeof(buf)) != sizeof(buf)) { + if (read(fd, buf, sizeof buf) != sizeof buf) { (void)close(fd); return FALSE; } (void)close(fd); - return memcmp(buf, armag, sizeof(buf)) == 0; + return memcmp(buf, armag, sizeof buf) == 0; } @@ -1,4 +1,4 @@ -.\" $NetBSD: make.1,v 1.282 2020/06/06 20:28:42 wiz Exp $ +.\" $NetBSD: make.1,v 1.289 2020/08/28 17:15:04 rillig Exp $ .\" .\" Copyright (c) 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" from: @(#)make.1 8.4 (Berkeley) 3/19/94 .\" -.Dd June 5, 2020 +.Dd August 28, 2020 .Dt BMAKE 1 .Os .Sh NAME @@ -166,8 +166,15 @@ Print the input graph after making everything, or before exiting on error. .It Ar "g3" Print the input graph before exiting on error. +.It Ar h +Print debugging information about hash table operations. .It Ar j Print debugging information about running multiple shells. +.It Ar L +Turn on lint checks. +This will throw errors for variable assignments that do not parse +correctly, at the time of assignment so the file and line number +are available. .It Ar l Print commands in Makefiles regardless of whether or not they are prefixed by .Ql @ @@ -311,7 +318,8 @@ as an argument). .It Fl n Display the commands that would have been executed, but do not actually execute them unless the target depends on the .MAKE special -source (see below). +source (see below) or the command is prefixed with +.Ql Ic + . .It Fl N Display the commands which would have been executed, but do not actually execute any of them; useful for debugging top-level makefiles @@ -412,37 +420,44 @@ or more sources. This creates a relationship where the targets .Dq depend on the sources -and are usually created from them. -The exact relationship between the target and the source is determined -by the operator that separates them. -The three operators are as follows: +and are customarily created from them. +A target is considered out-of-date if it does not exist, or if its +modification time is less than that of any of its sources. +An out-of-date target will be re-created, but not until all sources +have been examined and themselves re-created as needed. +Three operators may be used: .Bl -tag -width flag .It Ic \&: -A target is considered out-of-date if its modification time is less than -those of any of its sources. -Sources for a target accumulate over dependency lines when this operator -is used. -The target is removed if +Many dependency lines may name this target but only one may have +attached shell commands. +All sources named in all dependency lines are considered together, +and if needed the attached shell commands are run to create or +re-create the target. +If .Nm -is interrupted. +is interrupted, the target is removed. .It Ic \&! -Targets are always re-created, but not until all sources have been -examined and re-created as necessary. -Sources for a target accumulate over dependency lines when this operator -is used. -The target is removed if -.Nm -is interrupted. +The same, but the target is always re-created whether or not it is out +of date. .It Ic \&:: -If no sources are specified, the target is always re-created. -Otherwise, a target is considered out-of-date if any of its sources has -been modified more recently than the target. -Sources for a target do not accumulate over dependency lines when this -operator is used. -The target will not be removed if +Any dependency line may have attached shell commands, but each one +is handled independently: its sources are considered and the attached +shell commands are run if the target is out of date with respect to +(only) those sources. +Thus, different groups of the attached shell commands may be run +depending on the circumstances. +Furthermore, unlike +.Ic \&:, +for dependency lines with no sources, the attached shell +commands are always run. +Also unlike +.Ic \&:, +the target will not be removed if .Nm is interrupted. .El +All dependency lines mentioning a particular target must use the same +operator. .Pp Targets and sources may contain the shell wildcard values .Ql \&? , @@ -608,7 +623,7 @@ This shorter form is not recommended. .Pp If the variable name contains a dollar, then the name itself is expanded first. This allows almost arbitrary variable names, however names containing dollar, -braces, parenthesis, or whitespace are really best avoided! +braces, parentheses, or whitespace are really best avoided! .Pp If the result of expanding a variable contains a dollar sign .Pq Ql \&$ @@ -1126,6 +1141,9 @@ is set to the value of for all programs which .Nm executes. +.It Ev .SHELL +The pathname of the shell used to run target scripts. +It is read-only. .It Ev .TARGETS The list of targets explicitly specified on the command line, if any. .It Ev VPATH @@ -1171,7 +1189,7 @@ Replaces each word in the variable with its suffix. .It Cm \&:H Replaces each word in the variable with everything but the last component. .It Cm \&:M Ns Ar pattern -Select only those words that match +Selects only those words that match .Ar pattern . The standard shell wildcard characters .Pf ( Ql * , @@ -1195,11 +1213,11 @@ This is identical to but selects all words which do not match .Ar pattern . .It Cm \&:O -Order every word in variable alphabetically. +Orders every word in variable alphabetically. .It Cm \&:Or -Order every word in variable in reverse alphabetical order. +Orders every word in variable in reverse alphabetical order. .It Cm \&:Ox -Randomize words in variable. +Shuffles the words in variable. The results will be different each time you are referring to the modified variable; use the assignment with expansion .Pq Ql Cm \&:= @@ -1249,7 +1267,7 @@ If a .Va utc value is not provided or is 0, the current time is used. .It Cm \&:hash -Compute a 32-bit hash of the value and encode it as hex digits. +Computes a 32-bit hash of the value and encode it as hex digits. .It Cm \&:localtime[=utc] The value is a format string for .Xr strftime 3 , @@ -1259,7 +1277,7 @@ If a .Va utc value is not provided or is 0, the current time is used. .It Cm \&:tA -Attempt to convert variable to an absolute path using +Attempts to convert variable to an absolute path using .Xr realpath 3 , if that fails, the value is unchanged. .It Cm \&:tl @@ -1271,7 +1289,7 @@ This modifier sets the separator to the character If .Ar c is omitted, then no separator is used. -The common escapes (including octal numeric codes), work as expected. +The common escapes (including octal numeric codes) work as expected. .It Cm \&:tu Converts variable to upper-case letters. .It Cm \&:tW @@ -1287,21 +1305,21 @@ See also .Sm off .It Cm \&:S No \&/ Ar old_string No \&/ Ar new_string No \&/ Op Cm 1gW .Sm on -Modify the first occurrence of +Modifies the first occurrence of .Ar old_string -in the variable's value, replacing it with +in each word of the variable's value, replacing it with .Ar new_string . If a .Ql g -is appended to the last slash of the pattern, all occurrences +is appended to the last delimiter of the pattern, all occurrences in each word are replaced. If a .Ql 1 -is appended to the last slash of the pattern, only the first word +is appended to the last delimiter of the pattern, only the first occurrence is affected. If a .Ql W -is appended to the last slash of the pattern, +is appended to the last delimiter of the pattern, then the value is treated as a single word (possibly containing embedded white space). If @@ -1370,13 +1388,6 @@ as occur in the word or words it is found in; the .Ql W modifier causes the value to be treated as a single word (possibly containing embedded white space). -Note that -.Ql 1 -and -.Ql g -are orthogonal; the former specifies whether multiple words are -potentially affected, the latter whether multiple substitutions can -potentially occur within each affected word. .Pp As for the .Cm \&:S @@ -1387,9 +1398,9 @@ and are subjected to variable expansion before being parsed as regular expressions. .It Cm \&:T -Replaces each word in the variable with its last component. +Replaces each word in the variable with its last path component. .It Cm \&:u -Remove adjacent duplicate words (like +Removes adjacent duplicate words (like .Xr uniq 1 ) . .Sm off .It Cm \&:\&? Ar true_string Cm \&: Ar false_string @@ -1405,7 +1416,7 @@ usually contain variable expansions. A common error is trying to use expressions like .Dl ${NUMBERS:M42:?match:no} which actually tests defined(NUMBERS), -to determine is any words match "42" you need to use something like: +to determine if any words match "42" you need to use something like: .Dl ${"${NUMBERS:M42}" != \&"\&":?match:no} . .It Ar :old_string=new_string This is the @@ -1449,7 +1460,7 @@ in either the or .Ar old_string , only the first instance is treated specially (as the pattern character); -all subsequent instances are treated as regular characters +all subsequent instances are treated as regular characters. .Pp Variable expansion occurs in the normal fashion inside both .Ar old_string @@ -1466,11 +1477,10 @@ This is the loop expansion mechanism from the OSF Development Environment (ODE) make. Unlike .Cm \&.for -loops expansion occurs at the time of -reference. -Assign +loops, expansion occurs at the time of reference. +Assigns .Ar temp -to each word in the variable and evaluate +to each word in the variable and evaluates .Ar string . The ODE convention is that .Ar temp @@ -1481,7 +1491,7 @@ For example. However a single character variable is often more readable: .Dl ${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'${.newline}@} .It Cm \&:_[=var] -Save the current variable value in +Saves the current variable value in .Ql $_ or the named .Va var @@ -1502,7 +1512,7 @@ is used to save the result of the modifier which is later referenced using the index values from .Ql :range . .It Cm \&:U Ns Ar newval -If the variable is undefined +If the variable is undefined, .Ar newval is the value. If the variable is defined, the existing value is returned. @@ -1512,7 +1522,7 @@ It is handy for setting per-target CFLAGS for instance: If a value is only required if the variable is undefined, use: .Dl ${VAR:D:Unewval} .It Cm \&:D Ns Ar newval -If the variable is defined +If the variable is defined, .Ar newval is the value. .It Cm \&:L @@ -1641,7 +1651,7 @@ Returns the number of words in the value. .El \" :[range] .El .Sh INCLUDE STATEMENTS, CONDITIONALS AND FOR LOOPS -Makefile inclusion, conditional structures and for loops reminiscent +Makefile inclusion, conditional structures and for loops reminiscent of the C programming language are provided in .Nm . All such structures are identified by a line beginning with a single @@ -1687,7 +1697,7 @@ The possible conditionals are as follows: The message is printed along with the name of the makefile and line number, then .Nm -will exit. +will exit immediately. .It Ic .export Ar variable ... Export the specified global variable. If no variable list is provided, all globals are exported @@ -1876,7 +1886,7 @@ operator is not an integral value, then string comparison is performed between the expanded variables. If no relational operator is given, it is assumed that the expanded -variable is being compared against 0 or an empty string in the case +variable is being compared against 0, or an empty string in the case of a string comparison. .Pp When @@ -1917,7 +1927,7 @@ The syntax of a for loop is: .Pp .Bl -tag -compact -width Ds .It Ic \&.for Ar variable Oo Ar variable ... Oc Ic in Ar expression -.It Aq make-rules +.It Aq make-lines .It Ic \&.endfor .El .Pp @@ -1929,7 +1939,7 @@ On each iteration of the loop, one word is taken and assigned to each in order, and these .Ic variables are substituted into the -.Ic make-rules +.Ic make-lines inside the body of the for loop. The number of words must come out even; that is, if there are three iteration variables, the number of words provided must be a multiple diff --git a/bmake.cat1 b/bmake.cat1 index feb93698e34f..564e811737da 100644 --- a/bmake.cat1 +++ b/bmake.cat1 @@ -89,9 +89,15 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) [4mg3[24m Print the input graph before exiting on error. + [4mh[24m Print debugging information about hash table operations. + [4mj[24m Print debugging information about running multiple shells. + [4mL[24m Turn on lint checks. This will throw errors for variable + assignments that do not parse correctly, at the time of + assignment so the file and line number are available. + [4ml[24m Print commands in Makefiles regardless of whether or not they are prefixed by `@' or other "quiet" flags. Also known as "loud" behavior. @@ -188,7 +194,7 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) [1m-n [22mDisplay the commands that would have been executed, but do not actually execute them unless the target depends on the .MAKE spe- - cial source (see below). + cial source (see below) or the command is prefixed with `[1m+[22m'. [1m-N [22mDisplay the commands which would have been executed, but do not actually execute any of them; useful for debugging top-level @@ -260,25 +266,31 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) [1mFILE DEPENDENCY SPECIFICATIONS[0m Dependency lines consist of one or more targets, an operator, and zero or more sources. This creates a relationship where the targets ``depend'' - on the sources and are usually created from them. The exact relationship - between the target and the source is determined by the operator that sep- - arates them. The three operators are as follows: - - [1m: [22mA target is considered out-of-date if its modification time is less - than those of any of its sources. Sources for a target accumulate - over dependency lines when this operator is used. The target is - removed if [1mbmake [22mis interrupted. - - [1m! [22mTargets are always re-created, but not until all sources have been - examined and re-created as necessary. Sources for a target accumu- - late over dependency lines when this operator is used. The target - is removed if [1mbmake [22mis interrupted. - - [1m:: [22mIf no sources are specified, the target is always re-created. Oth- - erwise, a target is considered out-of-date if any of its sources - has been modified more recently than the target. Sources for a - target do not accumulate over dependency lines when this operator - is used. The target will not be removed if [1mbmake [22mis interrupted. + on the sources and are customarily created from them. A target is con- + sidered out-of-date if it does not exist, or if its modification time is + less than that of any of its sources. An out-of-date target will be re- + created, but not until all sources have been examined and themselves re- + created as needed. Three operators may be used: + + [1m: [22mMany dependency lines may name this target but only one may have + attached shell commands. All sources named in all dependency lines + are considered together, and if needed the attached shell commands + are run to create or re-create the target. If [1mbmake [22mis inter- + rupted, the target is removed. + + [1m! [22mThe same, but the target is always re-created whether or not it is + out of date. + + [1m:: [22mAny dependency line may have attached shell commands, but each one + is handled independently: its sources are considered and the + attached shell commands are run if the target is out of date with + respect to (only) those sources. Thus, different groups of the + attached shell commands may be run depending on the circumstances. + Furthermore, unlike [1m:, [22mfor dependency lines with no sources, the + attached shell commands are always run. Also unlike [1m:, [22mthe target + will not be removed if [1mbmake [22mis interrupted. + All dependency lines mentioning a particular target must use the same + operator. Targets and sources may contain the shell wildcard values `?', `*', `[]', and `{}'. The values `?', `*', and `[]' may only be used as part of the @@ -374,7 +386,7 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) If the variable name contains a dollar, then the name itself is expanded first. This allows almost arbitrary variable names, however names con- - taining dollar, braces, parenthesis, or whitespace are really best + taining dollar, braces, parentheses, or whitespace are really best avoided! If the result of expanding a variable contains a dollar sign (`$') the @@ -729,6 +741,9 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) contains a variable transform. `PWD' is set to the value of `[4m.OBJDIR[24m' for all programs which [1mbmake [22mexecutes. + .SHELL The pathname of the shell used to run target scripts. It + is read-only. + .TARGETS The list of targets explicitly specified on the command line, if any. @@ -765,7 +780,7 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) ponent. [1m:M[4m[22mpattern[0m - Select only those words that match [4mpattern[24m. The standard shell + Selects only those words that match [4mpattern[24m. The standard shell wildcard characters (`*', `?', and `[]') may be used. The wildcard characters may be escaped with a backslash (`\'). As a consequence of the way values are split into words, matched, and then joined, a @@ -779,11 +794,11 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) This is identical to `[1m:M[22m', but selects all words which do not match [4mpattern[24m. - [1m:O [22mOrder every word in variable alphabetically. + [1m:O [22mOrders every word in variable alphabetically. - [1m:Or [22mOrder every word in variable in reverse alphabetical order. + [1m:Or [22mOrders every word in variable in reverse alphabetical order. - [1m:Ox [22mRandomize words in variable. The results will be different each + [1m:Ox [22mShuffles the words in variable. The results will be different each time you are referring to the modified variable; use the assignment with expansion (`[1m:=[22m') to prevent such behavior. For example, @@ -821,13 +836,13 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) [4mutc[24m value is not provided or is 0, the current time is used. [1m:hash[0m - Compute a 32-bit hash of the value and encode it as hex digits. + Computes a 32-bit hash of the value and encode it as hex digits. [1m:localtime[=utc][0m The value is a format string for strftime(3), using localtime(3). If a [4mutc[24m value is not provided or is 0, the current time is used. - [1m:tA [22mAttempt to convert variable to an absolute path using realpath(3), + [1m:tA [22mAttempts to convert variable to an absolute path using realpath(3), if that fails, the value is unchanged. [1m:tl [22mConverts variable to lower-case letters. @@ -836,7 +851,7 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) Words in the variable are normally separated by a space on expan- sion. This modifier sets the separator to the character [4mc[24m. If [4mc[24m is omitted, then no separator is used. The common escapes (including - octal numeric codes), work as expected. + octal numeric codes) work as expected. [1m:tu [22mConverts variable to upper-case letters. @@ -847,20 +862,20 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) white space. See also `[1m:[@][22m'. [1m:S[22m/[4mold_string[24m/[4mnew_string[24m/[[1m1gW[22m] - Modify the first occurrence of [4mold_string[24m in the variable's value, - replacing it with [4mnew_string[24m. If a `g' is appended to the last - slash of the pattern, all occurrences in each word are replaced. If - a `1' is appended to the last slash of the pattern, only the first - word is affected. If a `W' is appended to the last slash of the - pattern, then the value is treated as a single word (possibly con- - taining embedded white space). If [4mold_string[24m begins with a caret - (`^'), [4mold_string[24m is anchored at the beginning of each word. If - [4mold_string[24m ends with a dollar sign (`$'), it is anchored at the end - of each word. Inside [4mnew_string[24m, an ampersand (`&') is replaced by - [4mold_string[24m (without any `^' or `$'). Any character may be used as a - delimiter for the parts of the modifier string. The anchoring, - ampersand and delimiter characters may be escaped with a backslash - (`\'). + Modifies the first occurrence of [4mold_string[24m in each word of the + variable's value, replacing it with [4mnew_string[24m. If a `g' is + appended to the last delimiter of the pattern, all occurrences in + each word are replaced. If a `1' is appended to the last delimiter + of the pattern, only the first occurrence is affected. If a `W' is + appended to the last delimiter of the pattern, then the value is + treated as a single word (possibly containing embedded white space). + If [4mold_string[24m begins with a caret (`^'), [4mold_string[24m is anchored at + the beginning of each word. If [4mold_string[24m ends with a dollar sign + (`$'), it is anchored at the end of each word. Inside [4mnew_string[24m, + an ampersand (`&') is replaced by [4mold_string[24m (without any `^' or + `$'). Any character may be used as a delimiter for the parts of the + modifier string. The anchoring, ampersand and delimiter characters + may be escaped with a backslash (`\'). Variable expansion occurs in the normal fashion inside both [4mold_string[24m and [4mnew_string[24m with the single exception that a backslash @@ -878,16 +893,13 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) instances of the search pattern [4mpattern[24m as occur in the word or words it is found in; the `W' modifier causes the value to be treated as a single word (possibly containing embedded white space). - Note that `1' and `g' are orthogonal; the former specifies whether - multiple words are potentially affected, the latter whether multiple - substitutions can potentially occur within each affected word. As for the [1m:S [22mmodifier, the [4mpattern[24m and [4mreplacement[24m are subjected to variable expansion before being parsed as regular expressions. - [1m:T [22mReplaces each word in the variable with its last component. + [1m:T [22mReplaces each word in the variable with its last path component. - [1m:u [22mRemove adjacent duplicate words (like uniq(1)). + [1m:u [22mRemoves adjacent duplicate words (like uniq(1)). [1m:?[4m[22mtrue_string[24m[1m:[4m[22mfalse_string[0m If the variable name (not its value), when parsed as a .if condi- @@ -898,7 +910,7 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) variable expansions. A common error is trying to use expressions like ${NUMBERS:M42:?match:no} - which actually tests defined(NUMBERS), to determine is any words + which actually tests defined(NUMBERS), to determine if any words match "42" you need to use something like: ${"${NUMBERS:M42}" != "":?match:no}. @@ -916,7 +928,7 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) pattern matching character ([4m%[24m) in either the [4mnew_string[24m or [4mold_string[24m, only the first instance is treated specially (as the pattern character); all subsequent instances are treated as regular - characters + characters. Variable expansion occurs in the normal fashion inside both [4mold_string[24m and [4mnew_string[24m with the single exception that a backslash @@ -925,17 +937,17 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) [1m:@[4m[22mtemp[24m[1m@[4m[22mstring[24m[1m@[0m This is the loop expansion mechanism from the OSF Development Envi- - ronment (ODE) make. Unlike [1m.for [22mloops expansion occurs at the time - of reference. Assign [4mtemp[24m to each word in the variable and evaluate - [4mstring[24m. The ODE convention is that [4mtemp[24m should start and end with a - period. For example. + ronment (ODE) make. Unlike [1m.for [22mloops, expansion occurs at the time + of reference. Assigns [4mtemp[24m to each word in the variable and evalu- + ates [4mstring[24m. The ODE convention is that [4mtemp[24m should start and end + with a period. For example. ${LINKS:@.LINK.@${LN} ${TARGET} ${.LINK.}@} However a single character variable is often more readable: ${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'${.newline}@} [1m:_[=var][0m - Save the current variable value in `$_' or the named [4mvar[24m for later + Saves the current variable value in `$_' or the named [4mvar[24m for later reference. Example usage: M_cmpv.units = 1 1000 1000000 @@ -948,7 +960,7 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) later referenced using the index values from `:range'. [1m:U[4m[22mnewval[0m - If the variable is undefined [4mnewval[24m is the value. If the variable + If the variable is undefined, [4mnewval[24m is the value. If the variable is defined, the existing value is returned. This is another ODE make feature. It is handy for setting per-target CFLAGS for instance: @@ -957,7 +969,7 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) ${VAR:D:Unewval} [1m:D[4m[22mnewval[0m - If the variable is defined [4mnewval[24m is the value. + If the variable is defined, [4mnewval[24m is the value. [1m:L [22mThe name of the variable is the value. @@ -1033,7 +1045,7 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) [1m# [22mReturns the number of words in the value. [1mINCLUDE STATEMENTS, CONDITIONALS AND FOR LOOPS[0m - Makefile inclusion, conditional structures and for loops reminiscent of + Makefile inclusion, conditional structures and for loops reminiscent of the C programming language are provided in [1mbmake[22m. All such structures are identified by a line beginning with a single dot (`.') character. Files are included with either [1m.include <[4m[22mfile[24m[1m> [22mor [1m.include "[4m[22mfile[24m[1m"[22m. Vari- @@ -1057,7 +1069,7 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) [1m.error [4m[22mmessage[0m The message is printed along with the name of the makefile and - line number, then [1mbmake [22mwill exit. + line number, then [1mbmake [22mwill exit immediately. [1m.export [4m[22mvariable[24m [4m...[0m Export the specified global variable. If no variable list is @@ -1191,7 +1203,7 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) variable expansion, either the left or right hand side of a `[1m==[22m' or `[1m!=[22m' operator is not an integral value, then string comparison is performed between the expanded variables. If no relational operator is given, it - is assumed that the expanded variable is being compared against 0 or an + is assumed that the expanded variable is being compared against 0, or an empty string in the case of a string comparison. When [1mbmake [22mis evaluating one of these conditional expressions, and it @@ -1210,12 +1222,12 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) The syntax of a for loop is: [1m.for [4m[22mvariable[24m [[4mvariable[24m [4m...[24m] [1min [4m[22mexpression[0m - <make-rules> + <make-lines> [1m.endfor[0m After the for [1mexpression [22mis evaluated, it is split into words. On each iteration of the loop, one word is taken and assigned to each [1mvariable[22m, - in order, and these [1mvariables [22mare substituted into the [1mmake-rules [22minside + in order, and these [1mvariables [22mare substituted into the [1mmake-lines [22minside the body of the for loop. The number of words must come out even; that is, if there are three iteration variables, the number of words provided must be a multiple of three. @@ -1556,4 +1568,4 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) There is no way of escaping a space character in a filename. -FreeBSD 11.3 June 5, 2020 FreeBSD 11.3 +FreeBSD 11.3 August 28, 2020 FreeBSD 11.3 diff --git a/bsd.after-import.mk b/bsd.after-import.mk index 23f30aa6c638..0d48f3c26648 100644 --- a/bsd.after-import.mk +++ b/bsd.after-import.mk @@ -1,4 +1,4 @@ -# $Id: bsd.after-import.mk,v 1.15 2018/12/30 17:14:24 sjg Exp $ +# $Id: bsd.after-import.mk,v 1.16 2020/07/12 03:39:01 sjg Exp $ # This makefile is for use when integrating bmake into a BSD build # system. Use this makefile after importing bmake. @@ -9,7 +9,7 @@ # The goal is to allow the benefits of autoconf without # the overhead of running configure. -all: _makefile +all: _makefile _utmakefile all: after-import # we rely on bmake @@ -37,7 +37,9 @@ SRCTOP := ${srctop} .endif # This lets us match what boot-strap does -.if !defined(HOST_OS) +.if defined(.MAKE.OS) +HOST_OS:= ${.MAKE.OS} +.elif !defined(HOST_OS) HOST_OS!= uname .endif @@ -107,5 +109,18 @@ _makefile: bootstrap ${MAKEFILE} @cmp -s ${.TARGET} ${.CURDIR}/Makefile || \ mv ${.TARGET} ${.CURDIR}/Makefile +_utmakefile: bootstrap ${MAKEFILE} + @echo Generating ${.CURDIR}/unit-tests/Makefile + @mkdir -p ${.CURDIR}/unit-tests + @(echo '# This is a generated file, do NOT edit!'; \ + echo '# See ${_this:S,${SRCTOP}/,,}'; \ + echo '#'; echo '# $$${HOST_OS}$$'; \ + ${MAKEFILE_SED} \ + -e '/^UNIT_TESTS/s,=.*,= $${srcdir},' \ + ${BMAKE_SRC}/unit-tests/Makefile ) > ${.TARGET} + @cmp -s ${.TARGET} ${.CURDIR}/unit-tests/Makefile || \ + mv ${.TARGET} ${.CURDIR}/unit-tests/Makefile + + .include <bsd.obj.mk> @@ -1,4 +1,4 @@ -/* $NetBSD: buf.c,v 1.26 2020/07/03 08:02:55 rillig Exp $ */ +/* $NetBSD: buf.c,v 1.37 2020/08/23 08:21:50 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -70,173 +70,123 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: buf.c,v 1.26 2020/07/03 08:02:55 rillig Exp $"; +static char rcsid[] = "$NetBSD: buf.c,v 1.37 2020/08/23 08:21:50 rillig Exp $"; #else #include <sys/cdefs.h> #ifndef lint #if 0 static char sccsid[] = "@(#)buf.c 8.1 (Berkeley) 6/6/93"; #else -__RCSID("$NetBSD: buf.c,v 1.26 2020/07/03 08:02:55 rillig Exp $"); +__RCSID("$NetBSD: buf.c,v 1.37 2020/08/23 08:21:50 rillig Exp $"); #endif #endif /* not lint */ #endif -/*- - * buf.c -- - * Functions for automatically-expanded buffers. - */ - -#include "make.h" -#include "buf.h" - -#ifndef max -#define max(a,b) ((a) > (b) ? (a) : (b)) -#endif +/* Functions for automatically-expanded null-terminated buffers. */ -#define BUF_DEF_SIZE 256 /* Default buffer size */ +#include <limits.h> +#include "make.h" -/*- - *----------------------------------------------------------------------- - * Buf_Expand_1 -- - * Extend buffer for single byte add. - * - *----------------------------------------------------------------------- - */ +/* Extend the buffer for adding a single byte. */ void Buf_Expand_1(Buffer *bp) { - bp->size += max(bp->size, 16); + bp->size += MAX(bp->size, 16); bp->buffer = bmake_realloc(bp->buffer, bp->size); } -/*- - *----------------------------------------------------------------------- - * Buf_AddBytes -- - * Add a number of bytes to the buffer. - * - * Results: - * None. - * - * Side Effects: - * Guess what? - * - *----------------------------------------------------------------------- - */ +/* Add the given bytes to the buffer. */ void -Buf_AddBytes(Buffer *bp, int numBytes, const Byte *bytesPtr) +Buf_AddBytes(Buffer *bp, const char *bytesPtr, size_t numBytes) { - int count = bp->count; - Byte *ptr; + size_t count = bp->count; + char *ptr; if (__predict_false(count + numBytes >= bp->size)) { - bp->size += max(bp->size, numBytes + 16); + bp->size += MAX(bp->size, numBytes + 16); bp->buffer = bmake_realloc(bp->buffer, bp->size); } ptr = bp->buffer + count; bp->count = count + numBytes; - ptr[numBytes] = 0; memcpy(ptr, bytesPtr, numBytes); + ptr[numBytes] = '\0'; } -/*- - *----------------------------------------------------------------------- - * Buf_GetAll -- - * Get all the available data at once. - * - * Results: - * A pointer to the data and the number of bytes available. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -Byte * -Buf_GetAll(Buffer *bp, int *numBytesPtr) +/* Add the bytes between start and end to the buffer. */ +void +Buf_AddBytesBetween(Buffer *bp, const char *start, const char *end) { + Buf_AddBytes(bp, start, (size_t)(end - start)); +} + +/* Add the given string to the buffer. */ +void +Buf_AddStr(Buffer *bp, const char *str) +{ + Buf_AddBytes(bp, str, strlen(str)); +} +/* Add the given number to the buffer. */ +void +Buf_AddInt(Buffer *bp, int n) +{ + enum { + bits = sizeof(int) * CHAR_BIT, + max_octal_digits = (bits + 2) / 3, + max_decimal_digits = /* at most */ max_octal_digits, + max_sign_chars = 1, + buf_size = max_sign_chars + max_decimal_digits + 1 + }; + char buf[buf_size]; + + size_t len = (size_t)snprintf(buf, sizeof buf, "%d", n); + Buf_AddBytes(bp, buf, len); +} + +/* Get the data (usually a string) from the buffer. + * The returned data is valid until the next modifying operation + * on the buffer. + * + * Returns the pointer to the data and optionally the length of the + * data in the buffer. */ +char * +Buf_GetAll(Buffer *bp, size_t *numBytesPtr) +{ if (numBytesPtr != NULL) *numBytesPtr = bp->count; - return bp->buffer; } -/*- - *----------------------------------------------------------------------- - * Buf_Empty -- - * Throw away bytes in a buffer. - * - * Results: - * None. - * - * Side Effects: - * The bytes are discarded. - * - *----------------------------------------------------------------------- - */ +/* Mark the buffer as empty, so it can be filled with data again. */ void Buf_Empty(Buffer *bp) { - bp->count = 0; - *bp->buffer = 0; + bp->buffer[0] = '\0'; } -/*- - *----------------------------------------------------------------------- - * Buf_Init -- - * Initialize a buffer. If no initial size is given, a reasonable - * default is used. - * - * Input: - * size Initial size for the buffer - * - * Results: - * A buffer to be given to other functions in this library. - * - * Side Effects: - * The buffer is created, the space allocated and pointers - * initialized. - * - *----------------------------------------------------------------------- - */ +/* Initialize a buffer. + * If the given initial size is 0, a reasonable default is used. */ void -Buf_Init(Buffer *bp, int size) +Buf_Init(Buffer *bp, size_t size) { if (size <= 0) { - size = BUF_DEF_SIZE; + size = 256; } bp->size = size; bp->count = 0; bp->buffer = bmake_malloc(size); - *bp->buffer = 0; + bp->buffer[0] = '\0'; } -/*- - *----------------------------------------------------------------------- - * Buf_Destroy -- - * Nuke a buffer and all its resources. - * - * Input: - * buf Buffer to destroy - * freeData TRUE if the data should be destroyed - * - * Results: - * Data buffer, NULL if freed - * - * Side Effects: - * The buffer is freed. - * - *----------------------------------------------------------------------- - */ -Byte * +/* Reset the buffer. + * If freeData is TRUE, the data from the buffer is freed as well. + * Otherwise it is kept and returned. */ +char * Buf_Destroy(Buffer *buf, Boolean freeData) { - Byte *data; - - data = buf->buffer; + char *data = buf->buffer; if (freeData) { free(data); data = NULL; @@ -249,42 +199,24 @@ Buf_Destroy(Buffer *buf, Boolean freeData) return data; } - -/*- - *----------------------------------------------------------------------- - * Buf_DestroyCompact -- - * Nuke a buffer and return its data. - * - * Input: - * buf Buffer to destroy - * - * Results: - * Data buffer - * - * Side Effects: - * If the buffer size is much greater than its content, - * a new buffer will be allocated and the old one freed. - * - *----------------------------------------------------------------------- - */ #ifndef BUF_COMPACT_LIMIT -# define BUF_COMPACT_LIMIT 128 /* worthwhile saving */ +# define BUF_COMPACT_LIMIT 128 /* worthwhile saving */ #endif -Byte * +/* Reset the buffer and return its data. + * + * If the buffer size is much greater than its content, + * a new buffer will be allocated and the old one freed. */ +char * Buf_DestroyCompact(Buffer *buf) { #if BUF_COMPACT_LIMIT > 0 - Byte *data; - if (buf->size - buf->count >= BUF_COMPACT_LIMIT) { /* We trust realloc to be smart */ - data = bmake_realloc(buf->buffer, buf->count + 1); - if (data) { - data[buf->count] = 0; - Buf_Destroy(buf, FALSE); - return data; - } + char *data = bmake_realloc(buf->buffer, buf->count + 1); + data[buf->count] = '\0'; + Buf_Destroy(buf, FALSE); + return data; } #endif return Buf_Destroy(buf, FALSE); @@ -1,4 +1,4 @@ -/* $NetBSD: buf.h,v 1.19 2017/05/31 22:02:06 maya Exp $ */ +/* $NetBSD: buf.h,v 1.28 2020/09/01 17:38:26 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -72,48 +72,54 @@ * from: @(#)buf.h 8.1 (Berkeley) 6/6/93 */ -/*- - * buf.h -- - * Header for users of the buf library. - */ +/* Automatically growing null-terminated buffers of characters. */ #ifndef MAKE_BUF_H #define MAKE_BUF_H -typedef char Byte; +#include <stddef.h> +/* An automatically growing null-terminated buffer of characters. */ typedef struct Buffer { - int size; /* Current size of the buffer */ - int count; /* Number of bytes in buffer */ - Byte *buffer; /* The buffer itself (zero terminated) */ + size_t size; /* Allocated size of the buffer, including the null */ + size_t count; /* Number of bytes in buffer, excluding the null */ + char *buffer; /* The buffer itself (always null-terminated) */ } Buffer; -/* If we aren't on netbsd, __predict_false() might not be defined. */ +/* If we aren't on NetBSD, __predict_false() might not be defined. */ #ifndef __predict_false #define __predict_false(x) (x) #endif -/* Buf_AddByte adds a single byte to a buffer. */ -#define Buf_AddByte(bp, byte) do { \ - int _count = ++(bp)->count; \ - char *_ptr; \ - if (__predict_false(_count >= (bp)->size)) \ - Buf_Expand_1(bp); \ - _ptr = (bp)->buffer + _count; \ - _ptr[-1] = (byte); \ - _ptr[0] = 0; \ - } while (0) +void Buf_Expand_1(Buffer *); -#define BUF_ERROR 256 +/* Buf_AddByte adds a single byte to a buffer. */ +static inline void MAKE_ATTR_UNUSED +Buf_AddByte(Buffer *bp, char byte) +{ + size_t count = ++bp->count; + char *ptr; + if (__predict_false(count >= bp->size)) + Buf_Expand_1(bp); + ptr = bp->buffer + count; + ptr[-1] = byte; + ptr[0] = 0; +} -#define Buf_Size(bp) ((bp)->count) +static inline size_t MAKE_ATTR_UNUSED +Buf_Size(const Buffer *bp) +{ + return bp->count; +} -void Buf_Expand_1(Buffer *); -void Buf_AddBytes(Buffer *, int, const Byte *); -Byte *Buf_GetAll(Buffer *, int *); +void Buf_AddBytes(Buffer *, const char *, size_t); +void Buf_AddBytesBetween(Buffer *, const char *, const char *); +void Buf_AddStr(Buffer *, const char *); +void Buf_AddInt(Buffer *, int); +char *Buf_GetAll(Buffer *, size_t *); void Buf_Empty(Buffer *); -void Buf_Init(Buffer *, int); -Byte *Buf_Destroy(Buffer *, Boolean); -Byte *Buf_DestroyCompact(Buffer *); +void Buf_Init(Buffer *, size_t); +char *Buf_Destroy(Buffer *, Boolean); +char *Buf_DestroyCompact(Buffer *); #endif /* MAKE_BUF_H */ @@ -1,4 +1,4 @@ -/* $NetBSD: compat.c,v 1.113 2020/07/03 08:13:23 rillig Exp $ */ +/* $NetBSD: compat.c,v 1.139 2020/08/30 20:08:47 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -70,14 +70,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: compat.c,v 1.113 2020/07/03 08:13:23 rillig Exp $"; +static char rcsid[] = "$NetBSD: compat.c,v 1.139 2020/08/30 20:08:47 rillig Exp $"; #else #include <sys/cdefs.h> #ifndef lint #if 0 static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94"; #else -__RCSID("$NetBSD: compat.c,v 1.113 2020/07/03 08:13:23 rillig Exp $"); +__RCSID("$NetBSD: compat.c,v 1.139 2020/08/30 20:08:47 rillig Exp $"); #endif #endif /* not lint */ #endif @@ -129,34 +129,24 @@ static void CompatDeleteTarget(GNode *gn) { if ((gn != NULL) && !Targ_Precious (gn)) { - char *p1; - char *file = Var_Value(TARGET, gn, &p1); + char *p1; + const char *file = Var_Value(TARGET, gn, &p1); if (!noExecute && eunlink(file) != -1) { Error("*** %s removed", file); } - free(p1); + bmake_free(p1); } } -/*- - *----------------------------------------------------------------------- - * CompatInterrupt -- - * Interrupt the creation of the current target and remove it if - * it ain't precious. - * - * Results: - * None. +/* Interrupt the creation of the current target and remove it if it ain't + * precious. Then exit. * - * Side Effects: - * The target is removed and the process exits. If .INTERRUPT exists, - * its commands are run first WITH INTERRUPTS IGNORED.. + * If .INTERRUPT exists, its commands are run first WITH INTERRUPTS IGNORED. * * XXX: is .PRECIOUS supposed to inhibit .INTERRUPT? I doubt it, but I've * left the logic alone for now. - dholland 20160826 - * - *----------------------------------------------------------------------- */ static void CompatInterrupt(int signo) @@ -190,7 +180,7 @@ CompatInterrupt(int signo) kill(myPid, signo); } } - + /*- *----------------------------------------------------------------------- * CompatRunCommand -- @@ -215,7 +205,7 @@ CompatRunCommand(void *cmdp, void *gnp) char *cmdStart; /* Start of expanded command */ char *cp, *bp; Boolean silent, /* Don't print command */ - doIt; /* Execute even if -n */ + doIt; /* Execute even if -n */ volatile Boolean errCheck; /* Check errors */ WAIT_T reason; /* Reason for child's death */ int status; /* Description of child's death */ @@ -224,21 +214,17 @@ CompatRunCommand(void *cmdp, void *gnp) LstNode cmdNode; /* Node where current command is located */ const char ** volatile av; /* Argument vector for thing to exec */ char ** volatile mav;/* Copy of the argument vector for freeing */ - int argc; /* Number of arguments in av or 0 if not - * dynamically allocated */ - Boolean local; /* TRUE if command should be executed - * locally */ Boolean useShell; /* TRUE if command should be executed * using a shell */ char * volatile cmd = (char *)cmdp; GNode *gn = (GNode *)gnp; - silent = gn->type & OP_SILENT; + silent = (gn->type & OP_SILENT) != 0; errCheck = !(gn->type & OP_IGNORE); doIt = FALSE; - cmdNode = Lst_Member(gn->commands, cmd); - cmdStart = Var_Subst(NULL, cmd, gn, VARF_WANTRES); + cmdNode = Lst_FindDatum(gn->commands, cmd); + cmdStart = Var_Subst(cmd, gn, VARE_WANTRES); /* * brk_string will return an argv with a NULL in av[0], thus causing @@ -252,10 +238,11 @@ CompatRunCommand(void *cmdp, void *gnp) return 0; } cmd = cmdStart; - Lst_Replace(cmdNode, cmdStart); + LstNode_Set(cmdNode, cmdStart); if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) { - (void)Lst_AtEnd(ENDNode->commands, cmdStart); + assert(ENDNode != NULL); + Lst_Append(ENDNode->commands, cmdStart); return 0; } if (strcmp(cmdStart, "...") == 0) { @@ -266,7 +253,7 @@ CompatRunCommand(void *cmdp, void *gnp) while ((*cmd == '@') || (*cmd == '-') || (*cmd == '+')) { switch (*cmd) { case '@': - silent = DEBUG(LOUD) ? FALSE : TRUE; + silent = !DEBUG(LOUD); break; case '-': errCheck = FALSE; @@ -330,7 +317,6 @@ CompatRunCommand(void *cmdp, void *gnp) if (DEBUG(JOB)) fprintf(debug_file, "Execute: '%s'\n", cmd); -again: if (useShell) { /* * We need to pass the command off to the shell, typically @@ -352,9 +338,8 @@ again: else shargv[shargc++] = "-c"; shargv[shargc++] = cmd; - shargv[shargc++] = NULL; + shargv[shargc] = NULL; av = shargv; - argc = 0; bp = NULL; mav = NULL; } else { @@ -362,16 +347,12 @@ again: * No meta-characters, so no need to exec a shell. Break the command * into words to form an argument vector we can execute. */ - mav = brk_string(cmd, &argc, TRUE, &bp); - if (mav == NULL) { - useShell = 1; - goto again; - } + Words words = Str_Words(cmd, FALSE); + mav = words.words; + bp = words.freeIt; av = (void *)mav; } - local = TRUE; - #ifdef USE_META if (useMeta) { meta_compat_start(); @@ -392,10 +373,7 @@ again: meta_compat_child(); } #endif - if (local) - (void)execvp(av[0], (char *const *)UNCONST(av)); - else - (void)execv(av[0], (char *const *)UNCONST(av)); + (void)execvp(av[0], (char *const *)UNCONST(av)); execError("exec", av[0]); _exit(1); } @@ -403,7 +381,9 @@ again: free(mav); free(bp); - Lst_Replace(cmdNode, NULL); + /* XXX: Memory management looks suspicious here. */ + /* XXX: Setting a list item to NULL is unexpected. */ + LstNode_SetNull(cmdNode); #ifdef USE_META if (useMeta) { @@ -436,18 +416,18 @@ again: #endif if (status != 0) { if (DEBUG(ERROR)) { - fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ", + fprintf(debug_file, "\n*** Failed target: %s\n*** Failed command: ", gn->name); - for (cp = cmd; *cp; ) { - if (isspace((unsigned char)*cp)) { + for (cp = cmd; *cp; ) { + if (isspace((unsigned char)*cp)) { fprintf(debug_file, " "); - while (isspace((unsigned char)*cp)) + while (isspace((unsigned char)*cp)) cp++; } else { fprintf(debug_file, "%c", *cp); - cp++; + cp++; } - } + } fprintf(debug_file, "\n"); } printf("*** Error code %d", status); @@ -502,7 +482,7 @@ again: return status; } - + /*- *----------------------------------------------------------------------- * Compat_Make -- @@ -544,14 +524,14 @@ Compat_Make(void *gnp, void *pgnp) Lst_ForEach(gn->children, Compat_Make, gn); if ((gn->flags & REMAKE) == 0) { gn->made = ABORTED; - pgn->flags &= ~REMAKE; + pgn->flags &= ~(unsigned)REMAKE; goto cohorts; } - if (Lst_Member(gn->iParents, pgn) != NULL) { + if (Lst_FindDatum(gn->implicitParents, pgn) != NULL) { char *p1; Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn); - free(p1); + bmake_free(p1); } /* @@ -614,7 +594,7 @@ Compat_Make(void *gnp, void *pgnp) Lst_ForEach(gn->commands, CompatRunCommand, gn); curTarg = NULL; } else { - Job_Touch(gn, gn->type & OP_SILENT); + Job_Touch(gn, (gn->type & OP_SILENT) != 0); } } else { gn->made = ERROR; @@ -640,7 +620,7 @@ Compat_Make(void *gnp, void *pgnp) Make_TimeStamp(pgn, gn); } } else if (keepgoing) { - pgn->flags &= ~REMAKE; + pgn->flags &= ~(unsigned)REMAKE; } else { PrintOnError(gn, "\nStop."); exit(1); @@ -650,18 +630,19 @@ Compat_Make(void *gnp, void *pgnp) * Already had an error when making this beastie. Tell the parent * to abort. */ - pgn->flags &= ~REMAKE; + pgn->flags &= ~(unsigned)REMAKE; } else { - if (Lst_Member(gn->iParents, pgn) != NULL) { + if (Lst_FindDatum(gn->implicitParents, pgn) != NULL) { char *p1; - Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn); - free(p1); + const char *target = Var_Value(TARGET, gn, &p1); + Var_Set(IMPSRC, target != NULL ? target : "", pgn); + bmake_free(p1); } switch(gn->made) { case BEINGMADE: Error("Graph cycles through %s", gn->name); gn->made = ERROR; - pgn->flags &= ~REMAKE; + pgn->flags &= ~(unsigned)REMAKE; break; case MADE: if ((gn->type & OP_EXEC) == 0) { @@ -683,22 +664,11 @@ cohorts: Lst_ForEach(gn->cohorts, Compat_Make, pgnp); return 0; } - -/*- - *----------------------------------------------------------------------- - * Compat_Run -- - * Initialize this mode and start making. + +/* Initialize this module and start making. * * Input: - * targs List of target nodes to re-create - * - * Results: - * None. - * - * Side Effects: - * Guess what? - * - *----------------------------------------------------------------------- + * targs The target nodes to re-create */ void Compat_Run(Lst targs) @@ -732,10 +702,10 @@ Compat_Run(Lst targs) gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); if (gn != NULL) { Compat_Make(gn, gn); - if (gn->made == ERROR) { - PrintOnError(gn, "\nStop."); - exit(1); - } + if (gn->made == ERROR) { + PrintOnError(gn, "\nStop."); + exit(1); + } } } @@ -756,8 +726,8 @@ Compat_Run(Lst targs) * could not be made due to errors. */ errors = 0; - while (!Lst_IsEmpty (targs)) { - gn = (GNode *)Lst_DeQueue(targs); + while (!Lst_IsEmpty(targs)) { + gn = Lst_Dequeue(targs); Compat_Make(gn, gn); if (gn->made == UPTODATE) { @@ -1,4 +1,4 @@ -/* $NetBSD: cond.c,v 1.79 2020/07/09 22:34:08 sjg Exp $ */ +/* $NetBSD: cond.c,v 1.106 2020/08/29 13:38:48 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -70,14 +70,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: cond.c,v 1.79 2020/07/09 22:34:08 sjg Exp $"; +static char rcsid[] = "$NetBSD: cond.c,v 1.106 2020/08/29 13:38:48 rillig Exp $"; #else #include <sys/cdefs.h> #ifndef lint #if 0 static char sccsid[] = "@(#)cond.c 8.2 (Berkeley) 1/2/94"; #else -__RCSID("$NetBSD: cond.c,v 1.79 2020/07/09 22:34:08 sjg Exp $"); +__RCSID("$NetBSD: cond.c,v 1.106 2020/08/29 13:38:48 rillig Exp $"); #endif #endif /* not lint */ #endif @@ -91,14 +91,10 @@ __RCSID("$NetBSD: cond.c,v 1.79 2020/07/09 22:34:08 sjg Exp $"); * */ -#include <assert.h> -#include <ctype.h> -#include <errno.h> /* For strtoul() error checking */ +#include <errno.h> -#include "make.h" -#include "hash.h" -#include "dir.h" -#include "buf.h" +#include "make.h" +#include "dir.h" /* * The parsing of conditional expressions is based on this grammar: @@ -121,8 +117,7 @@ __RCSID("$NetBSD: cond.c,v 1.79 2020/07/09 22:34:08 sjg Exp $"); * T -> ! T * op -> == | != | > | < | >= | <= * - * 'symbol' is some other symbol to which the default function (condDefProc) - * is applied. + * 'symbol' is some other symbol to which the default function is applied. * * Tokens are scanned from the 'condExpr' string. The scanner (CondToken) * will return TOK_AND for '&' and '&&', TOK_OR for '|' and '||', @@ -141,46 +136,16 @@ typedef enum { TOK_LPAREN, TOK_RPAREN, TOK_EOF, TOK_NONE, TOK_ERROR } Token; -/*- - * Structures to handle elegantly the different forms of #if's. The - * last two fields are stored in condInvert and condDefProc, respectively. - */ -static void CondPushBack(Token); -static int CondGetArg(Boolean, char **, char **, const char *); -static Boolean CondDoDefined(int, const char *); -static int CondStrMatch(const void *, const void *); -static Boolean CondDoMake(int, const char *); -static Boolean CondDoExists(int, const char *); -static Boolean CondDoTarget(int, const char *); -static Boolean CondDoCommands(int, const char *); -static Boolean CondCvtArg(char *, double *); -static Token CondToken(Boolean); -static Token CondT(Boolean); -static Token CondF(Boolean); static Token CondE(Boolean); -static int do_Cond_EvalExpression(Boolean *); +static CondEvalResult do_Cond_EvalExpression(Boolean *); -static const struct If { - const char *form; /* Form of if */ - int formlen; /* Length of form */ - Boolean doNot; /* TRUE if default function should be negated */ - Boolean (*defProc)(int, const char *); /* Default function to apply */ -} ifs[] = { - { "def", 3, FALSE, CondDoDefined }, - { "ndef", 4, TRUE, CondDoDefined }, - { "make", 4, FALSE, CondDoMake }, - { "nmake", 5, TRUE, CondDoMake }, - { "", 0, FALSE, CondDoDefined }, - { NULL, 0, FALSE, NULL } -}; - -static const struct If *if_info; /* Info for current statement */ -static char *condExpr; /* The expression to parse */ -static Token condPushBack=TOK_NONE; /* Single push-back token used in +static const struct If *if_info; /* Info for current statement */ +static const char *condExpr; /* The expression to parse */ +static Token condPushBack = TOK_NONE; /* Single push-back token used in * parsing */ -static unsigned int cond_depth = 0; /* current .if nesting level */ -static unsigned int cond_min_depth = 0; /* depth at makefile open */ +static unsigned int cond_depth = 0; /* current .if nesting level */ +static unsigned int cond_min_depth = 0; /* depth at makefile open */ /* * Indicate when we should be strict about lhs of comparisons. @@ -194,58 +159,38 @@ static Boolean lhsStrict; static int istoken(const char *str, const char *tok, size_t len) { - return strncmp(str, tok, len) == 0 && !isalpha((unsigned char)str[len]); + return strncmp(str, tok, len) == 0 && !isalpha((unsigned char)str[len]); } -/*- - *----------------------------------------------------------------------- - * CondPushBack -- - * Push back the most recent token read. We only need one level of - * this, so the thing is just stored in 'condPushback'. - * - * Input: - * t Token to push back into the "stream" - * - * Results: - * None. - * - * Side Effects: - * condPushback is overwritten. - * - *----------------------------------------------------------------------- - */ +/* Push back the most recent token read. We only need one level of + * this, so the thing is just stored in 'condPushback'. */ static void CondPushBack(Token t) { condPushBack = t; } - + /*- - *----------------------------------------------------------------------- - * CondGetArg -- - * Find the argument of a built-in function. + * Parse the argument of a built-in function. * * Results: - * The length of the argument and the address of the argument. - * - * Side Effects: - * The pointer is set to point to the closing parenthesis of the - * function call. - * - *----------------------------------------------------------------------- + * The length of the argument. + * *argPtr receives the argument as string. + * *linePtr is updated to point behind the ')' of the function call. */ static int -CondGetArg(Boolean doEval, char **linePtr, char **argPtr, const char *func) +CondGetArg(Boolean doEval, const char **linePtr, char **argPtr, + const char *func) { - char *cp; - int argLen; - Buffer buf; - int paren_depth; - char ch; + const char *cp; + Buffer buf; + int paren_depth; + char ch; + size_t argLen; cp = *linePtr; if (func != NULL) - /* Skip opening '(' - verfied by caller */ + /* Skip opening '(' - verified by caller */ cp++; if (*cp == '\0') { @@ -283,23 +228,19 @@ CondGetArg(Boolean doEval, char **linePtr, char **argPtr, const char *func) * variable, so we don't do it too. Nor do we return an error, * though perhaps we should... */ - char *cp2; - int len; - void *freeIt; - - cp2 = Var_Parse(cp, VAR_CMD, VARF_UNDEFERR| - (doEval ? VARF_WANTRES : 0), - &len, &freeIt); - Buf_AddBytes(&buf, strlen(cp2), cp2); + int len; + void *freeIt; + VarEvalFlags eflags = VARE_UNDEFERR | (doEval ? VARE_WANTRES : 0); + const char *cp2 = Var_Parse(cp, VAR_CMD, eflags, &len, &freeIt); + Buf_AddStr(&buf, cp2); free(freeIt); cp += len; continue; } if (ch == '(') paren_depth++; - else - if (ch == ')' && --paren_depth < 0) - break; + else if (ch == ')' && --paren_depth < 0) + break; Buf_AddByte(&buf, *cp); cp++; } @@ -313,105 +254,49 @@ CondGetArg(Boolean doEval, char **linePtr, char **argPtr, const char *func) if (func != NULL && *cp++ != ')') { Parse_Error(PARSE_WARNING, "Missing closing parenthesis for %s()", - func); + func); return 0; } *linePtr = cp; return argLen; } - -/*- - *----------------------------------------------------------------------- - * CondDoDefined -- - * Handle the 'defined' function for conditionals. - * - * Results: - * TRUE if the given variable is defined. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ + +/* Test whether the given variable is defined. */ static Boolean CondDoDefined(int argLen MAKE_ATTR_UNUSED, const char *arg) { - char *p1; - Boolean result; - - if (Var_Value(arg, VAR_CMD, &p1) != NULL) { - result = TRUE; - } else { - result = FALSE; - } - - free(p1); + char *freeIt; + Boolean result = Var_Value(arg, VAR_CMD, &freeIt) != NULL; + bmake_free(freeIt); return result; } - -/*- - *----------------------------------------------------------------------- - * CondStrMatch -- - * Front-end for Str_Match so it returns 0 on match and non-zero - * on mismatch. Callback function for CondDoMake via Lst_Find - * - * Results: - * 0 if string matches pattern - * - * Side Effects: - * None - * - *----------------------------------------------------------------------- - */ -static int -CondStrMatch(const void *string, const void *pattern) + +/* Wrapper around Str_Match, to be used by Lst_Find. */ +static Boolean +CondFindStrMatch(const void *string, const void *pattern) { - return !Str_Match(string, pattern); + return Str_Match(string, pattern); } - -/*- - *----------------------------------------------------------------------- - * CondDoMake -- - * Handle the 'make' function for conditionals. - * - * Results: - * TRUE if the given target is being made. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ + +/* See if the given target is being made. */ static Boolean CondDoMake(int argLen MAKE_ATTR_UNUSED, const char *arg) { - return Lst_Find(create, arg, CondStrMatch) != NULL; + return Lst_Find(create, CondFindStrMatch, arg) != NULL; } - -/*- - *----------------------------------------------------------------------- - * CondDoExists -- - * See if the given file exists. - * - * Results: - * TRUE if the file exists and FALSE if it does not. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ + +/* See if the given file exists. */ static Boolean CondDoExists(int argLen MAKE_ATTR_UNUSED, const char *arg) { Boolean result; - char *path; + char *path; path = Dir_FindFile(arg, dirSearchPath); if (DEBUG(COND)) { fprintf(debug_file, "exists(%s) result is \"%s\"\n", - arg, path ? path : ""); + arg, path ? path : ""); } if (path != NULL) { result = TRUE; @@ -421,68 +306,39 @@ CondDoExists(int argLen MAKE_ATTR_UNUSED, const char *arg) } return result; } - -/*- - *----------------------------------------------------------------------- - * CondDoTarget -- - * See if the given node exists and is an actual target. - * - * Results: - * TRUE if the node exists as a target and FALSE if it does not. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ + +/* See if the given node exists and is an actual target. */ static Boolean CondDoTarget(int argLen MAKE_ATTR_UNUSED, const char *arg) { - GNode *gn; + GNode *gn; gn = Targ_FindNode(arg, TARG_NOCREATE); return gn != NULL && !OP_NOP(gn->type); } -/*- - *----------------------------------------------------------------------- - * CondDoCommands -- - * See if the given node exists and is an actual target with commands - * associated with it. - * - * Results: - * TRUE if the node exists as a target and has commands associated with - * it and FALSE if it does not. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ +/* See if the given node exists and is an actual target with commands + * associated with it. */ static Boolean CondDoCommands(int argLen MAKE_ATTR_UNUSED, const char *arg) { - GNode *gn; + GNode *gn; gn = Targ_FindNode(arg, TARG_NOCREATE); return gn != NULL && !OP_NOP(gn->type) && !Lst_IsEmpty(gn->commands); } - + /*- - *----------------------------------------------------------------------- - * CondCvtArg -- - * Convert the given number into a double. - * We try a base 10 or 16 integer conversion first, if that fails - * then we try a floating point conversion instead. + * Convert the given number into a double. + * We try a base 10 or 16 integer conversion first, if that fails + * then we try a floating point conversion instead. * * Results: * Sets 'value' to double value of string. - * Returns 'true' if the convertion suceeded - * - *----------------------------------------------------------------------- + * Returns TRUE if the conversion succeeded. */ static Boolean -CondCvtArg(char *str, double *value) +CondCvtArg(const char *str, double *value) { char *eptr, ech; unsigned long l_val; @@ -510,33 +366,28 @@ CondCvtArg(char *str, double *value) } /*- - *----------------------------------------------------------------------- - * CondGetString -- - * Get a string from a variable reference or an optionally quoted - * string. This is called for the lhs and rhs of string compares. + * Get a string from a variable reference or an optionally quoted + * string. This is called for the lhs and rhs of string compares. * * Results: - * Sets freeIt if needed, - * Sets quoted if string was quoted, - * Returns NULL on error, - * else returns string - absent any quotes. + * Returns the string, absent any quotes, or NULL on error. + * Sets quoted if the string was quoted. + * Sets freeIt if needed. * * Side Effects: - * Moves condExpr to end of this token. - * - * - *----------------------------------------------------------------------- + * Moves condExpr past the end of this token. */ /* coverity:[+alloc : arg-*2] */ -static char * +static const char * CondGetString(Boolean doEval, Boolean *quoted, void **freeIt, Boolean strictLHS) { Buffer buf; - char *cp; - char *str; - int len; - int qt; - char *start; + const char *cp; + const char *str; + int len; + Boolean qt; + const char *start; + VarEvalFlags eflags; Buf_Init(&buf, 0); str = NULL; @@ -573,9 +424,9 @@ CondGetString(Boolean doEval, Boolean *quoted, void **freeIt, Boolean strictLHS) break; case '$': /* if we are in quotes, then an undefined variable is ok */ - str = Var_Parse(condExpr, VAR_CMD, - ((!qt && doEval) ? VARF_UNDEFERR : 0) | - (doEval ? VARF_WANTRES : 0), &len, freeIt); + eflags = ((!qt && doEval) ? VARE_UNDEFERR : 0) | + (doEval ? VARE_WANTRES : 0); + str = Var_Parse(condExpr, VAR_CMD, eflags, &len, freeIt); if (str == var_Error) { if (*freeIt) { free(*freeIt); @@ -596,7 +447,7 @@ CondGetString(Boolean doEval, Boolean *quoted, void **freeIt, Boolean strictLHS) */ if ((condExpr == start + len) && (*condExpr == '\0' || - isspace((unsigned char) *condExpr) || + isspace((unsigned char)*condExpr) || strchr("!=><)", *condExpr))) { goto cleanup; } @@ -610,12 +461,12 @@ CondGetString(Boolean doEval, Boolean *quoted, void **freeIt, Boolean strictLHS) free(*freeIt); *freeIt = NULL; } - str = NULL; /* not finished yet */ - condExpr--; /* don't skip over next char */ + str = NULL; /* not finished yet */ + condExpr--; /* don't skip over next char */ break; default: if (strictLHS && !qt && *start != '$' && - !isdigit((unsigned char) *start)) { + !isdigit((unsigned char)*start)) { /* lhs must be quoted, a variable reference or number */ if (*freeIt) { free(*freeIt); @@ -628,43 +479,51 @@ CondGetString(Boolean doEval, Boolean *quoted, void **freeIt, Boolean strictLHS) break; } } - got_str: - str = Buf_GetAll(&buf, NULL); - *freeIt = str; - cleanup: +got_str: + *freeIt = Buf_GetAll(&buf, NULL); + str = *freeIt; +cleanup: Buf_Destroy(&buf, FALSE); return str; } - + +/* The different forms of #if's. */ +static const struct If { + const char *form; /* Form of if */ + size_t formlen; /* Length of form */ + Boolean doNot; /* TRUE if default function should be negated */ + Boolean (*defProc)(int, const char *); /* Default function to apply */ +} ifs[] = { + { "def", 3, FALSE, CondDoDefined }, + { "ndef", 4, TRUE, CondDoDefined }, + { "make", 4, FALSE, CondDoMake }, + { "nmake", 5, TRUE, CondDoMake }, + { "", 0, FALSE, CondDoDefined }, + { NULL, 0, FALSE, NULL } +}; + /*- - *----------------------------------------------------------------------- - * CondToken -- - * Return the next token from the input. - * - * Results: - * A Token for the next lexical token in the stream. + * Return the next token from the input. * * Side Effects: * condPushback will be set back to TOK_NONE if it is used. - * - *----------------------------------------------------------------------- */ static Token compare_expression(Boolean doEval) { - Token t; - char *lhs; - char *rhs; - char *op; - void *lhsFree; - void *rhsFree; + Token t; + const char *lhs; + const char *rhs; + const char *op; + void *lhsFree; + void *rhsFree; Boolean lhsQuoted; Boolean rhsQuoted; - double left, right; + double left, right; t = TOK_ERROR; rhs = NULL; - lhsFree = rhsFree = FALSE; + lhsFree = rhsFree = NULL; lhsQuoted = rhsQuoted = FALSE; /* @@ -678,7 +537,7 @@ compare_expression(Boolean doEval) /* * Skip whitespace to get to the operator */ - while (isspace((unsigned char) *condExpr)) + while (isspace((unsigned char)*condExpr)) condExpr++; /* @@ -688,39 +547,39 @@ compare_expression(Boolean doEval) */ op = condExpr; switch (*condExpr) { - case '!': - case '=': - case '<': - case '>': - if (condExpr[1] == '=') { - condExpr += 2; - } else { - condExpr += 1; - } - break; - default: - if (!doEval) { - t = TOK_FALSE; - goto done; - } - /* For .ifxxx "..." check for non-empty string. */ - if (lhsQuoted) { - t = lhs[0] != 0; - goto done; - } - /* For .ifxxx <number> compare against zero */ - if (CondCvtArg(lhs, &left)) { - t = left != 0.0; - goto done; - } - /* For .if ${...} check for non-empty string (defProc is ifdef). */ - if (if_info->form[0] == 0) { - t = lhs[0] != 0; - goto done; - } - /* Otherwise action default test ... */ - t = if_info->defProc(strlen(lhs), lhs) != if_info->doNot; + case '!': + case '=': + case '<': + case '>': + if (condExpr[1] == '=') { + condExpr += 2; + } else { + condExpr += 1; + } + break; + default: + if (!doEval) { + t = TOK_FALSE; goto done; + } + /* For .ifxxx "..." check for non-empty string. */ + if (lhsQuoted) { + t = lhs[0] != 0; + goto done; + } + /* For .ifxxx <number> compare against zero */ + if (CondCvtArg(lhs, &left)) { + t = left != 0.0; + goto done; + } + /* For .if ${...} check for non-empty string (defProc is ifdef). */ + if (if_info->form[0] == 0) { + t = lhs[0] != 0; + goto done; + } + /* Otherwise action default test ... */ + t = if_info->defProc(strlen(lhs), lhs) != if_info->doNot; + goto done; } while (isspace((unsigned char)*condExpr)) @@ -742,16 +601,16 @@ compare_expression(Boolean doEval) } if (rhsQuoted || lhsQuoted) { -do_string_compare: + do_string_compare: if (((*op != '!') && (*op != '=')) || (op[1] != '=')) { Parse_Error(PARSE_WARNING, - "String comparison operator should be either == or !="); + "String comparison operator should be either == or !="); goto done; } if (DEBUG(COND)) { fprintf(debug_file, "lhs = \"%s\", rhs = \"%s\", op = %.2s\n", - lhs, rhs, op); + lhs, rhs, op); } /* * Null-terminate rhs and perform the comparison. @@ -773,9 +632,9 @@ do_string_compare: if (DEBUG(COND)) { fprintf(debug_file, "left = %f, right = %f, op = %.2s\n", left, - right, op); + right, op); } - switch(op[0]) { + switch (op[0]) { case '!': if (op[1] != '=') { Parse_Error(PARSE_WARNING, @@ -816,21 +675,23 @@ done: } static int -get_mpt_arg(Boolean doEval, char **linePtr, char **argPtr, const char *func MAKE_ATTR_UNUSED) +get_mpt_arg(Boolean doEval, const char **linePtr, char **argPtr, + const char *func MAKE_ATTR_UNUSED) { /* * Use Var_Parse to parse the spec in parens and return * TOK_TRUE if the resulting string is empty. */ - int length; - void *freeIt; - char *val; - char *cp = *linePtr; + int length; + void *val_freeIt; + const char *val; + const char *cp = *linePtr; /* We do all the work here and return the result as the length */ *argPtr = NULL; - val = Var_Parse(cp - 1, VAR_CMD, doEval ? VARF_WANTRES : 0, &length, &freeIt); + val = Var_Parse(cp - 1, VAR_CMD, doEval ? VARE_WANTRES : 0, &length, + &val_freeIt); /* * Advance *linePtr to beyond the closing ). Note that * we subtract one because 'length' is calculated from 'cp - 1'. @@ -838,12 +699,12 @@ get_mpt_arg(Boolean doEval, char **linePtr, char **argPtr, const char *func MAKE *linePtr = cp - 1 + length; if (val == var_Error) { - free(freeIt); + free(val_freeIt); return -1; } /* A variable is empty when it just contains spaces... 4/15/92, christos */ - while (isspace(*(unsigned char *)val)) + while (isspace((unsigned char)val[0])) val++; /* @@ -851,7 +712,7 @@ get_mpt_arg(Boolean doEval, char **linePtr, char **argPtr, const char *func MAKE * true/false here. */ length = *val ? 2 : 1; - free(freeIt); + free(val_freeIt); return length; } @@ -865,32 +726,32 @@ static Token compare_function(Boolean doEval) { static const struct fn_def { - const char *fn_name; - int fn_name_len; - int (*fn_getarg)(Boolean, char **, char **, const char *); - Boolean (*fn_proc)(int, const char *); + const char *fn_name; + size_t fn_name_len; + int (*fn_getarg)(Boolean, const char **, char **, const char *); + Boolean (*fn_proc)(int, const char *); } fn_defs[] = { - { "defined", 7, CondGetArg, CondDoDefined }, - { "make", 4, CondGetArg, CondDoMake }, - { "exists", 6, CondGetArg, CondDoExists }, - { "empty", 5, get_mpt_arg, CondDoEmpty }, - { "target", 6, CondGetArg, CondDoTarget }, - { "commands", 8, CondGetArg, CondDoCommands }, - { NULL, 0, NULL, NULL }, + { "defined", 7, CondGetArg, CondDoDefined }, + { "make", 4, CondGetArg, CondDoMake }, + { "exists", 6, CondGetArg, CondDoExists }, + { "empty", 5, get_mpt_arg, CondDoEmpty }, + { "target", 6, CondGetArg, CondDoTarget }, + { "commands", 8, CondGetArg, CondDoCommands }, + { NULL, 0, NULL, NULL }, }; const struct fn_def *fn_def; - Token t; - char *arg = NULL; - int arglen; - char *cp = condExpr; - char *cp1; + Token t; + char *arg = NULL; + int arglen; + const char *cp = condExpr; + const char *cp1; for (fn_def = fn_defs; fn_def->fn_name != NULL; fn_def++) { if (!istoken(cp, fn_def->fn_name, fn_def->fn_name_len)) continue; cp += fn_def->fn_name_len; /* There can only be whitespace before the '(' */ - while (isspace(*(unsigned char *)cp)) + while (isspace((unsigned char)*cp)) cp++; if (*cp != '(') break; @@ -921,7 +782,7 @@ compare_function(Boolean doEval) * expression. */ arglen = CondGetArg(doEval, &cp, &arg, NULL); - for (cp1 = cp; isspace(*(unsigned char *)cp1); cp1++) + for (cp1 = cp; isspace((unsigned char)*cp1); cp1++) continue; if (*cp1 == '=' || *cp1 == '!') return compare_expression(doEval); @@ -1015,7 +876,7 @@ CondToken(Boolean doEval) static Token CondT(Boolean doEval) { - Token t; + Token t; t = CondToken(doEval); @@ -1045,7 +906,7 @@ CondT(Boolean doEval) } return t; } - + /*- *----------------------------------------------------------------------- * CondF -- @@ -1063,7 +924,7 @@ CondT(Boolean doEval) static Token CondF(Boolean doEval) { - Token l, o; + Token l, o; l = CondT(doEval); if (l != TOK_ERROR) { @@ -1091,7 +952,7 @@ CondF(Boolean doEval) } return l; } - + /*- *----------------------------------------------------------------------- * CondE -- @@ -1109,7 +970,7 @@ CondF(Boolean doEval) static Token CondE(Boolean doEval) { - Token l, o; + Token l, o; l = CondF(doEval); if (l != TOK_ERROR) { @@ -1139,6 +1000,31 @@ CondE(Boolean doEval) return l; } +static CondEvalResult +do_Cond_EvalExpression(Boolean *value) +{ + + switch (CondE(TRUE)) { + case TOK_TRUE: + if (CondToken(TRUE) == TOK_EOF) { + *value = TRUE; + return COND_PARSE; + } + break; + case TOK_FALSE: + if (CondToken(TRUE) == TOK_EOF) { + *value = FALSE; + return COND_PARSE; + } + break; + default: + case TOK_ERROR: + break; + } + + return COND_INVALID; +} + /*- *----------------------------------------------------------------------- * Cond_EvalExpression -- @@ -1153,16 +1039,16 @@ CondE(Boolean doEval) * (*value) is set to the boolean value of the condition * * Side Effects: - * None. - * + * Any effects from evaluating the variables. *----------------------------------------------------------------------- */ -int -Cond_EvalExpression(const struct If *info, char *line, Boolean *value, int eprint, Boolean strictLHS) +CondEvalResult +Cond_EvalExpression(const struct If *info, char *line, Boolean *value, + int eprint, Boolean strictLHS) { static const struct If *dflt_info; const struct If *sv_if_info = if_info; - char *sv_condExpr = condExpr; + const char *sv_condExpr = condExpr; Token sv_condPushBack = condPushBack; int rval; @@ -1173,7 +1059,7 @@ Cond_EvalExpression(const struct If *info, char *line, Boolean *value, int eprin if (info == NULL && (info = dflt_info) == NULL) { /* Scan for the entry for .if - it can't be first */ - for (info = ifs; ; info++) + for (info = ifs;; info++) if (info->form[0] == 0) break; dflt_info = info; @@ -1196,32 +1082,7 @@ Cond_EvalExpression(const struct If *info, char *line, Boolean *value, int eprin return rval; } -static int -do_Cond_EvalExpression(Boolean *value) -{ - - switch (CondE(TRUE)) { - case TOK_TRUE: - if (CondToken(TRUE) == TOK_EOF) { - *value = TRUE; - return COND_PARSE; - } - break; - case TOK_FALSE: - if (CondToken(TRUE) == TOK_EOF) { - *value = FALSE; - return COND_PARSE; - } - break; - default: - case TOK_ERROR: - break; - } - - return COND_INVALID; -} - /*- *----------------------------------------------------------------------- * Cond_Eval -- @@ -1241,35 +1102,31 @@ do_Cond_EvalExpression(Boolean *value) * COND_SKIP if should skip lines after the conditional * COND_INVALID if not a valid conditional. * - * Side Effects: - * None. - * * Note that the states IF_ACTIVE and ELSE_ACTIVE are only different in order - * to detect splurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF) + * to detect spurious .else lines (as are SKIP_TO_ELSE and SKIP_TO_ENDIF), * otherwise .else could be treated as '.elif 1'. - * *----------------------------------------------------------------------- */ -int +CondEvalResult Cond_Eval(char *line) { -#define MAXIF 128 /* maximum depth of .if'ing */ -#define MAXIF_BUMP 32 /* how much to grow by */ + enum { MAXIF = 128 }; /* maximum depth of .if'ing */ + enum { MAXIF_BUMP = 32 }; /* how much to grow by */ enum if_states { IF_ACTIVE, /* .if or .elif part active */ ELSE_ACTIVE, /* .else part active */ SEARCH_FOR_ELIF, /* searching for .elif/else to execute */ - SKIP_TO_ELSE, /* has been true, but not seen '.else' */ + SKIP_TO_ELSE, /* has been true, but not seen '.else' */ SKIP_TO_ENDIF /* nothing else to execute */ }; static enum if_states *cond_state = NULL; static unsigned int max_if_depth = MAXIF; const struct If *ifp; - Boolean isElif; - Boolean value; - int level; /* Level at which to report errors. */ - enum if_states state; + Boolean isElif; + Boolean value; + int level; /* Level at which to report errors. */ + enum if_states state; level = PARSE_FATAL; if (!cond_state) { @@ -1292,7 +1149,8 @@ Cond_Eval(char *line) } /* Return state for previous conditional */ cond_depth--; - return cond_state[cond_depth] <= ELSE_ACTIVE ? COND_PARSE : COND_SKIP; + return cond_state[cond_depth] <= ELSE_ACTIVE + ? COND_PARSE : COND_SKIP; } /* Quite likely this is 'else' or 'elif' */ @@ -1336,7 +1194,7 @@ Cond_Eval(char *line) * function is, etc. -- by looking in the table of valid "ifs" */ line += 2; - for (ifp = ifs; ; ifp++) { + for (ifp = ifs;; ifp++) { if (ifp->form == NULL) return COND_INVALID; if (istoken(ifp->form, line, ifp->formlen)) { @@ -1372,8 +1230,8 @@ Cond_Eval(char *line) * can need more than the default. */ max_if_depth += MAXIF_BUMP; - cond_state = bmake_realloc(cond_state, max_if_depth * - sizeof(*cond_state)); + cond_state = bmake_realloc(cond_state, + max_if_depth * sizeof(*cond_state)); } state = cond_state[cond_depth]; cond_depth++; @@ -1400,21 +1258,6 @@ Cond_Eval(char *line) return COND_PARSE; } - - -/*- - *----------------------------------------------------------------------- - * Cond_End -- - * Make sure everything's clean at the end of a makefile. - * - * Results: - * None. - * - * Side Effects: - * Parse_Error will be called if open conditionals are around. - * - *----------------------------------------------------------------------- - */ void Cond_restore_depth(unsigned int saved_depth) { @@ -1,4 +1,4 @@ -/* $NetBSD: dir.c,v 1.76 2020/07/03 08:13:23 rillig Exp $ */ +/* $NetBSD: dir.c,v 1.135 2020/09/02 04:32:13 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -70,14 +70,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: dir.c,v 1.76 2020/07/03 08:13:23 rillig Exp $"; +static char rcsid[] = "$NetBSD: dir.c,v 1.135 2020/09/02 04:32:13 rillig Exp $"; #else #include <sys/cdefs.h> #ifndef lint #if 0 static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 1/2/94"; #else -__RCSID("$NetBSD: dir.c,v 1.76 2020/07/03 08:13:23 rillig Exp $"); +__RCSID("$NetBSD: dir.c,v 1.135 2020/09/02 04:32:13 rillig Exp $"); #endif #endif /* not lint */ #endif @@ -143,10 +143,20 @@ __RCSID("$NetBSD: dir.c,v 1.76 2020/07/03 08:13:23 rillig Exp $"); #include <stdio.h> #include "make.h" -#include "hash.h" #include "dir.h" #include "job.h" + +#define DIR_DEBUG0(fmt) \ + if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt) + +#define DIR_DEBUG1(fmt, arg1) \ + if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt, arg1) + +#define DIR_DEBUG2(fmt, arg1, arg2) \ + if (!DEBUG(DIR)) (void) 0; else fprintf(debug_file, fmt, arg1, arg2) + + /* * A search path consists of a Lst of Path structures. A Path structure * has in it the name of the directory and a hash table of all the files @@ -217,37 +227,35 @@ __RCSID("$NetBSD: dir.c,v 1.76 2020/07/03 08:13:23 rillig Exp $"); * in a cache for when Dir_MTime was actually called. */ -Lst dirSearchPath; /* main search path */ +Lst dirSearchPath; /* main search path */ -static Lst openDirectories; /* the list of all open directories */ +static Lst openDirectories; /* the list of all open directories */ /* * Variables for gathering statistics on the efficiency of the hashing * mechanism. */ -static int hits, /* Found in directory cache */ - misses, /* Sad, but not evil misses */ - nearmisses, /* Found under search path */ - bigmisses; /* Sought by itself */ - -static Path *dot; /* contents of current directory */ -static Path *cur; /* contents of current directory, if not dot */ -static Path *dotLast; /* a fake path entry indicating we need to - * look for . last */ -static Hash_Table mtimes; /* Results of doing a last-resort stat in - * Dir_FindFile -- if we have to go to the - * system to find the file, we might as well - * have its mtime on record. XXX: If this is done - * way early, there's a chance other rules will - * have already updated the file, in which case - * we'll update it again. Generally, there won't - * be two rules to update a single file, so this - * should be ok, but... */ - -static Hash_Table lmtimes; /* same as mtimes but for lstat */ - -static int DirFindName(const void *, const void *); -static int DirMatchFiles(const char *, Path *, Lst); +static int hits; /* Found in directory cache */ +static int misses; /* Sad, but not evil misses */ +static int nearmisses; /* Found under search path */ +static int bigmisses; /* Sought by itself */ + +static Path *dot; /* contents of current directory */ +static Path *cur; /* contents of current directory, if not dot */ +static Path *dotLast; /* a fake path entry indicating we need to + * look for . last */ + +/* Results of doing a last-resort stat in Dir_FindFile -- if we have to go to + * the system to find the file, we might as well have its mtime on record. + * + * XXX: If this is done way early, there's a chance other rules will have + * already updated the file, in which case we'll update it again. Generally, + * there won't be two rules to update a single file, so this should be ok, + * but... */ +static Hash_Table mtimes; + +static Hash_Table lmtimes; /* same as mtimes but for lstat */ + static void DirExpandCurly(const char *, const char *, Lst, Lst); static void DirExpandInt(const char *, Lst, Lst); static int DirPrintWord(void *, void *); @@ -259,23 +267,28 @@ static char *DirLookupAbs(Path *, const char *, const char *); /* - * We use stat(2) a lot, cache the results + * We use stat(2) a lot, cache the results. * mtime and mode are all we care about. */ struct cache_st { - time_t lmtime; /* lstat */ - time_t mtime; /* stat */ - mode_t mode; + time_t lmtime; /* lstat */ + time_t mtime; /* stat */ + mode_t mode; }; /* minimize changes below */ -#define CST_LSTAT 1 -#define CST_UPDATE 2 +typedef enum { + CST_LSTAT = 0x01, /* call lstat(2) instead of stat(2) */ + CST_UPDATE = 0x02 /* ignore existing cached entry */ +} CachedStatsFlags; +/* Returns 0 and the result of stat(2) or lstat(2) in *mst, or -1 on error. */ static int -cached_stats(Hash_Table *htp, const char *pathname, struct stat *st, int flags) +cached_stats(Hash_Table *htp, const char *pathname, struct make_stat *mst, + CachedStatsFlags flags) { Hash_Entry *entry; + struct stat sys_st; struct cache_st *cst; int rc; @@ -284,83 +297,74 @@ cached_stats(Hash_Table *htp, const char *pathname, struct stat *st, int flags) entry = Hash_FindEntry(htp, pathname); - if (entry && (flags & CST_UPDATE) == 0) { - cst = entry->clientPtr; + if (entry && !(flags & CST_UPDATE)) { + cst = Hash_GetValue(entry); - memset(st, 0, sizeof(*st)); - st->st_mode = cst->mode; - st->st_mtime = (flags & CST_LSTAT) ? cst->lmtime : cst->mtime; - if (st->st_mtime) { - if (DEBUG(DIR)) { - fprintf(debug_file, "Using cached time %s for %s\n", - Targ_FmtTime(st->st_mtime), pathname); - } + mst->mst_mode = cst->mode; + mst->mst_mtime = (flags & CST_LSTAT) ? cst->lmtime : cst->mtime; + if (mst->mst_mtime) { + DIR_DEBUG2("Using cached time %s for %s\n", + Targ_FmtTime(mst->mst_mtime), pathname); return 0; } } - rc = (flags & CST_LSTAT) ? lstat(pathname, st) : stat(pathname, st); + rc = (flags & CST_LSTAT) + ? lstat(pathname, &sys_st) + : stat(pathname, &sys_st); if (rc == -1) return -1; - if (st->st_mtime == 0) - st->st_mtime = 1; /* avoid confusion with missing file */ + if (sys_st.st_mtime == 0) + sys_st.st_mtime = 1; /* avoid confusion with missing file */ + + mst->mst_mode = sys_st.st_mode; + mst->mst_mtime = sys_st.st_mtime; - if (!entry) + if (entry == NULL) entry = Hash_CreateEntry(htp, pathname, NULL); - if (!entry->clientPtr) { - entry->clientPtr = bmake_malloc(sizeof(*cst)); - memset(entry->clientPtr, 0, sizeof(*cst)); + if (Hash_GetValue(entry) == NULL) { + Hash_SetValue(entry, bmake_malloc(sizeof(*cst))); + memset(Hash_GetValue(entry), 0, sizeof(*cst)); } - cst = entry->clientPtr; - if ((flags & CST_LSTAT)) { - cst->lmtime = st->st_mtime; + cst = Hash_GetValue(entry); + if (flags & CST_LSTAT) { + cst->lmtime = sys_st.st_mtime; } else { - cst->mtime = st->st_mtime; - } - cst->mode = st->st_mode; - if (DEBUG(DIR)) { - fprintf(debug_file, " Caching %s for %s\n", - Targ_FmtTime(st->st_mtime), pathname); + cst->mtime = sys_st.st_mtime; } + cst->mode = sys_st.st_mode; + DIR_DEBUG2(" Caching %s for %s\n", + Targ_FmtTime(sys_st.st_mtime), pathname); return 0; } int -cached_stat(const char *pathname, void *st) +cached_stat(const char *pathname, struct make_stat *st) { return cached_stats(&mtimes, pathname, st, 0); } int -cached_lstat(const char *pathname, void *st) +cached_lstat(const char *pathname, struct make_stat *st) { return cached_stats(&lmtimes, pathname, st, CST_LSTAT); } -/*- - *----------------------------------------------------------------------- - * Dir_Init -- - * initialize things for this module - * - * Results: - * none - * - * Side Effects: - * some directories may be opened. - *----------------------------------------------------------------------- - */ +/* Initialize things for this module. */ void -Dir_Init(const char *cdname) +Dir_Init(void) +{ + dirSearchPath = Lst_Init(); + openDirectories = Lst_Init(); + Hash_InitTable(&mtimes, 0); + Hash_InitTable(&lmtimes, 0); +} + +void +Dir_InitDir(const char *cdname) { - if (!cdname) { - dirSearchPath = Lst_Init(FALSE); - openDirectories = Lst_Init(FALSE); - Hash_InitTable(&mtimes, 0); - Hash_InitTable(&lmtimes, 0); - return; - } Dir_InitCur(cdname); dotLast = bmake_malloc(sizeof(Path)); @@ -371,7 +375,7 @@ Dir_Init(const char *cdname) } /* - * Called by Dir_Init() and whenever .CURDIR is assigned to. + * Called by Dir_InitDir and whenever .CURDIR is assigned to. */ void Dir_InitCur(const char *cdname) @@ -397,18 +401,8 @@ Dir_InitCur(const char *cdname) } } -/*- - *----------------------------------------------------------------------- - * Dir_InitDot -- - * (re)initialize "dot" (current/object directory) path hash - * - * Results: - * none - * - * Side Effects: - * some directories may be opened. - *----------------------------------------------------------------------- - */ +/* (Re)initialize "dot" (current/object directory) path hash. + * Some directories may be opened. */ void Dir_InitDot(void) { @@ -416,8 +410,8 @@ Dir_InitDot(void) LstNode ln; /* Remove old entry from openDirectories, but do not destroy. */ - ln = Lst_Member(openDirectories, dot); - (void)Lst_Remove(openDirectories, ln); + ln = Lst_FindDatum(openDirectories, dot); + Lst_Remove(openDirectories, ln); } dot = Dir_AddDir(NULL, "."); @@ -432,21 +426,10 @@ Dir_InitDot(void) * to make sure it's not destroyed. */ dot->refCount += 1; - Dir_SetPATH(); /* initialize */ + Dir_SetPATH(); /* initialize */ } -/*- - *----------------------------------------------------------------------- - * Dir_End -- - * cleanup things for this module - * - * Results: - * none - * - * Side Effects: - * none - *----------------------------------------------------------------------- - */ +/* Clean up things for this module. */ void Dir_End(void) { @@ -460,9 +443,9 @@ Dir_End(void) Dir_Destroy(dotLast); Dir_Destroy(dot); Dir_ClearPath(dirSearchPath); - Lst_Destroy(dirSearchPath, NULL); + Lst_Free(dirSearchPath); Dir_ClearPath(openDirectories); - Lst_Destroy(openDirectories, NULL); + Lst_Free(openDirectories); Hash_DeleteTable(&mtimes); #endif } @@ -475,122 +458,100 @@ Dir_End(void) void Dir_SetPATH(void) { - LstNode ln; /* a list element */ + LstNode ln; /* a list element */ Path *p; - Boolean hasLastDot = FALSE; /* true we should search dot last */ + Boolean hasLastDot = FALSE; /* true if we should search dot last */ Var_Delete(".PATH", VAR_GLOBAL); - if (Lst_Open(dirSearchPath) == SUCCESS) { - if ((ln = Lst_First(dirSearchPath)) != NULL) { - p = (Path *)Lst_Datum(ln); - if (p == dotLast) { - hasLastDot = TRUE; - Var_Append(".PATH", dotLast->name, VAR_GLOBAL); - } + Lst_Open(dirSearchPath); + if ((ln = Lst_First(dirSearchPath)) != NULL) { + p = LstNode_Datum(ln); + if (p == dotLast) { + hasLastDot = TRUE; + Var_Append(".PATH", dotLast->name, VAR_GLOBAL); } + } - if (!hasLastDot) { - if (dot) - Var_Append(".PATH", dot->name, VAR_GLOBAL); - if (cur) - Var_Append(".PATH", cur->name, VAR_GLOBAL); - } + if (!hasLastDot) { + if (dot) + Var_Append(".PATH", dot->name, VAR_GLOBAL); + if (cur) + Var_Append(".PATH", cur->name, VAR_GLOBAL); + } - while ((ln = Lst_Next(dirSearchPath)) != NULL) { - p = (Path *)Lst_Datum(ln); - if (p == dotLast) - continue; - if (p == dot && hasLastDot) - continue; - Var_Append(".PATH", p->name, VAR_GLOBAL); - } + while ((ln = Lst_Next(dirSearchPath)) != NULL) { + p = LstNode_Datum(ln); + if (p == dotLast) + continue; + if (p == dot && hasLastDot) + continue; + Var_Append(".PATH", p->name, VAR_GLOBAL); + } - if (hasLastDot) { - if (dot) - Var_Append(".PATH", dot->name, VAR_GLOBAL); - if (cur) - Var_Append(".PATH", cur->name, VAR_GLOBAL); - } - Lst_Close(dirSearchPath); + if (hasLastDot) { + if (dot) + Var_Append(".PATH", dot->name, VAR_GLOBAL); + if (cur) + Var_Append(".PATH", cur->name, VAR_GLOBAL); } + Lst_Close(dirSearchPath); } -/*- - *----------------------------------------------------------------------- - * DirFindName -- - * See if the Path structure describes the same directory as the - * given one by comparing their names. Called from Dir_AddDir via - * Lst_Find when searching the list of open directories. - * - * Input: - * p Current name - * dname Desired name - * - * Results: - * 0 if it is the same. Non-zero otherwise - * - * Side Effects: - * None - *----------------------------------------------------------------------- - */ -static int -DirFindName(const void *p, const void *dname) +/* See if the Path structure describes the same directory as the + * given one by comparing their names. Called from Dir_AddDir via + * Lst_Find when searching the list of open directories. */ +static Boolean +DirFindName(const void *p, const void *desiredName) { - return strcmp(((const Path *)p)->name, dname); + return strcmp(((const Path *)p)->name, desiredName) == 0; } -/*- - *----------------------------------------------------------------------- - * Dir_HasWildcards -- - * see if the given name has any wildcard characters in it - * be careful not to expand unmatching brackets or braces. - * XXX: This code is not 100% correct. ([^]] fails etc.) - * I really don't think that make(1) should be expanding - * patterns, because then you have to set a mechanism for - * escaping the expansion! +/* See if the given name has any wildcard characters in it. Be careful not to + * expand unmatching brackets or braces. + * + * XXX: This code is not 100% correct ([^]] fails etc.). I really don't think + * that make(1) should be expanding patterns, because then you have to set a + * mechanism for escaping the expansion! * * Input: * name name to check * * Results: * returns TRUE if the word should be expanded, FALSE otherwise - * - * Side Effects: - * none - *----------------------------------------------------------------------- */ Boolean -Dir_HasWildcards(char *name) +Dir_HasWildcards(const char *name) { - char *cp; - int wild = 0, brace = 0, bracket = 0; + const char *cp; + Boolean wild = FALSE; + int braces = 0, brackets = 0; for (cp = name; *cp; cp++) { - switch(*cp) { + switch (*cp) { case '{': - brace++; - wild = 1; - break; + braces++; + wild = TRUE; + break; case '}': - brace--; - break; + braces--; + break; case '[': - bracket++; - wild = 1; - break; + brackets++; + wild = TRUE; + break; case ']': - bracket--; - break; + brackets--; + break; case '?': case '*': - wild = 1; - break; + wild = TRUE; + break; default: - break; + break; } } - return wild && bracket == 0 && brace == 0; + return wild && brackets == 0 && braces == 0; } /*- @@ -607,20 +568,17 @@ Dir_HasWildcards(char *name) * p Directory to search * expansion Place to store the results * - * Results: - * Always returns 0 - * * Side Effects: * File names are added to the expansions lst. The directory will be * fully hashed when this is done. *----------------------------------------------------------------------- */ -static int +static void DirMatchFiles(const char *pattern, Path *p, Lst expansions) { - Hash_Search search; /* Index into the directory's table */ - Hash_Entry *entry; /* Current entry in the table */ - Boolean isDot; /* TRUE if the directory being searched is . */ + Hash_Search search; /* Index into the directory's table */ + Hash_Entry *entry; /* Current entry in the table */ + Boolean isDot; /* TRUE if the directory being searched is . */ isDot = (*p->name == '.' && p->name[1] == '\0'); @@ -638,13 +596,75 @@ DirMatchFiles(const char *pattern, Path *p, Lst expansions) ((entry->name[0] != '.') || (pattern[0] == '.'))) { - (void)Lst_AtEnd(expansions, - (isDot ? bmake_strdup(entry->name) : - str_concat(p->name, entry->name, - STR_ADDSLASH))); + Lst_Append(expansions, + (isDot ? bmake_strdup(entry->name) : + str_concat3(p->name, "/", entry->name))); } } - return 0; +} + +/* Find the next closing brace in the string, taking nested braces into + * account. */ +static const char * +closing_brace(const char *p) +{ + int nest = 0; + while (*p != '\0') { + if (*p == '}' && nest == 0) + break; + if (*p == '{') + nest++; + if (*p == '}') + nest--; + p++; + } + return p; +} + +/* Find the next closing brace or comma in the string, taking nested braces + * into account. */ +static const char * +separator_comma(const char *p) +{ + int nest = 0; + while (*p != '\0') { + if ((*p == '}' || *p == ',') && nest == 0) + break; + if (*p == '{') + nest++; + if (*p == '}') + nest--; + p++; + } + return p; +} + +static Boolean +contains_wildcard(const char *p) +{ + for (; *p != '\0'; p++) { + switch (*p) { + case '*': + case '?': + case '{': + case '[': + return TRUE; + } + } + return FALSE; +} + +static char * +concat3(const char *a, size_t a_len, const char *b, size_t b_len, + const char *c, size_t c_len) +{ + size_t s_len = a_len + b_len + c_len; + char *s = bmake_malloc(s_len + 1); + memcpy(s, a, a_len); + memcpy(s + a_len, b, b_len); + memcpy(s + a_len + b_len, c, c_len); + s[s_len] = '\0'; + return s; } /*- @@ -672,91 +692,41 @@ DirMatchFiles(const char *pattern, Path *p, Lst expansions) static void DirExpandCurly(const char *word, const char *brace, Lst path, Lst expansions) { - const char *end; /* Character after the closing brace */ - const char *cp; /* Current position in brace clause */ - const char *start; /* Start of current piece of brace clause */ - int bracelevel; /* Number of braces we've seen. If we see a - * right brace when this is 0, we've hit the - * end of the clause. */ - char *file; /* Current expansion */ - int otherLen; /* The length of the other pieces of the - * expansion (chars before and after the - * clause in 'word') */ - char *cp2; /* Pointer for checking for wildcards in - * expansion before calling Dir_Expand */ - - start = brace+1; + const char *prefix, *middle, *piece, *middle_end, *suffix; + size_t prefix_len, suffix_len; - /* - * Find the end of the brace clause first, being wary of nested brace - * clauses. - */ - for (end = start, bracelevel = 0; *end != '\0'; end++) { - if (*end == '{') { - bracelevel++; - } else if ((*end == '}') && (bracelevel-- == 0)) { - break; - } - } - if (*end == '\0') { - Error("Unterminated {} clause \"%s\"", start); + /* Split the word into prefix '{' middle '}' suffix. */ + + middle = brace + 1; + middle_end = closing_brace(middle); + if (*middle_end == '\0') { + Error("Unterminated {} clause \"%s\"", middle); return; - } else { - end++; } - otherLen = brace - word + strlen(end); - for (cp = start; cp < end; cp++) { - /* - * Find the end of this piece of the clause. - */ - bracelevel = 0; - while (*cp != ',') { - if (*cp == '{') { - bracelevel++; - } else if ((*cp == '}') && (bracelevel-- <= 0)) { - break; - } - cp++; - } - /* - * Allocate room for the combination and install the three pieces. - */ - file = bmake_malloc(otherLen + cp - start + 1); - if (brace != word) { - strncpy(file, word, brace-word); - } - if (cp != start) { - strncpy(&file[brace-word], start, cp-start); - } - strcpy(&file[(brace-word)+(cp-start)], end); + prefix = word; + prefix_len = (size_t)(brace - prefix); + suffix = middle_end + 1; + suffix_len = strlen(suffix); - /* - * See if the result has any wildcards in it. If we find one, call - * Dir_Expand right away, telling it to place the result on our list - * of expansions. - */ - for (cp2 = file; *cp2 != '\0'; cp2++) { - switch(*cp2) { - case '*': - case '?': - case '{': - case '[': - Dir_Expand(file, path, expansions); - goto next; - } - } - if (*cp2 == '\0') { - /* - * Hit the end w/o finding any wildcards, so stick the expansion - * on the end of the list. - */ - (void)Lst_AtEnd(expansions, file); - } else { - next: + /* Split the middle into pieces, separated by commas. */ + + piece = middle; + while (piece < middle_end + 1) { + const char *piece_end = separator_comma(piece); + size_t piece_len = (size_t)(piece_end - piece); + + char *file = concat3(prefix, prefix_len, piece, piece_len, + suffix, suffix_len); + + if (contains_wildcard(file)) { + Dir_Expand(file, path, expansions); free(file); + } else { + Lst_Append(expansions, file); } - start = cp+1; + + piece = piece_end + 1; /* skip over the comma or closing brace */ } } @@ -784,32 +754,18 @@ DirExpandCurly(const char *word, const char *brace, Lst path, Lst expansions) static void DirExpandInt(const char *word, Lst path, Lst expansions) { - LstNode ln; /* Current node */ - Path *p; /* Directory in the node */ + LstNode ln; /* Current node */ - if (Lst_Open(path) == SUCCESS) { - while ((ln = Lst_Next(path)) != NULL) { - p = (Path *)Lst_Datum(ln); - DirMatchFiles(word, p, expansions); - } - Lst_Close(path); + Lst_Open(path); + while ((ln = Lst_Next(path)) != NULL) { + Path *p = LstNode_Datum(ln); + DirMatchFiles(word, p, expansions); } + Lst_Close(path); } -/*- - *----------------------------------------------------------------------- - * DirPrintWord -- - * Print a word in the list of expansions. Callback for Dir_Expand - * when DEBUG(DIR), via Lst_ForEach. - * - * Results: - * === 0 - * - * Side Effects: - * The passed word is printed, followed by a space. - * - *----------------------------------------------------------------------- - */ +/* Print a word in the list of expansions. + * Callback for Dir_Expand when DEBUG(DIR), via Lst_ForEach. */ static int DirPrintWord(void *word, void *dummy MAKE_ATTR_UNUSED) { @@ -836,16 +792,18 @@ DirPrintWord(void *word, void *dummy MAKE_ATTR_UNUSED) * * Side Effects: * Directories may be opened. Who knows? + * Undefined behavior if the word is really in read-only memory. *----------------------------------------------------------------------- */ void Dir_Expand(const char *word, Lst path, Lst expansions) { - const char *cp; + const char *cp; - if (DEBUG(DIR)) { - fprintf(debug_file, "Expanding \"%s\"... ", word); - } + assert(path != NULL); + assert(expansions != NULL); + + DIR_DEBUG1("Expanding \"%s\"... ", word); cp = strchr(word, '{'); if (cp) { @@ -872,13 +830,12 @@ Dir_Expand(const char *word, Lst path, Lst expansions) /* * Back up to the start of the component */ - char *dirpath; - while (cp > word && *cp != '/') { cp--; } if (cp != word) { char sc; + char *dirpath; /* * If the glob isn't in the first component, try and find * all the components up to the one with a wildcard. @@ -898,10 +855,10 @@ Dir_Expand(const char *word, Lst path, Lst expansions) char *dp = &dirpath[strlen(dirpath) - 1]; if (*dp == '/') *dp = '\0'; - path = Lst_Init(FALSE); + path = Lst_Init(); (void)Dir_AddDir(path, dirpath); - DirExpandInt(cp+1, path, expansions); - Lst_Destroy(path, NULL); + DirExpandInt(cp + 1, path, expansions); + Lst_Free(path); } } else { /* @@ -948,21 +905,17 @@ Dir_Expand(const char *word, Lst path, Lst expansions) */ static char * DirLookup(Path *p, const char *name MAKE_ATTR_UNUSED, const char *cp, - Boolean hasSlash MAKE_ATTR_UNUSED) + Boolean hasSlash MAKE_ATTR_UNUSED) { - char *file; /* the current filename to check */ + char *file; /* the current filename to check */ - if (DEBUG(DIR)) { - fprintf(debug_file, " %s ...\n", p->name); - } + DIR_DEBUG1(" %s ...\n", p->name); if (Hash_FindEntry(&p->files, cp) == NULL) return NULL; - file = str_concat(p->name, cp, STR_ADDSLASH); - if (DEBUG(DIR)) { - fprintf(debug_file, " returning %s\n", file); - } + file = str_concat3(p->name, "/", cp); + DIR_DEBUG1(" returning %s\n", file); p->hits += 1; hits += 1; return file; @@ -986,11 +939,11 @@ DirLookup(Path *p, const char *name MAKE_ATTR_UNUSED, const char *cp, static char * DirLookupSubdir(Path *p, const char *name) { - struct stat stb; /* Buffer for stat, if necessary */ - char *file; /* the current filename to check */ + struct make_stat mst; + char *file; /* the current filename to check */ if (p != dot) { - file = str_concat(p->name, name, STR_ADDSLASH); + file = str_concat3(p->name, "/", name); } else { /* * Checking in dot -- DON'T put a leading ./ on the thing. @@ -998,11 +951,9 @@ DirLookupSubdir(Path *p, const char *name) file = bmake_strdup(name); } - if (DEBUG(DIR)) { - fprintf(debug_file, "checking %s ...\n", file); - } + DIR_DEBUG1("checking %s ...\n", file); - if (cached_stat(file, &stb) == 0) { + if (cached_stat(file, &mst) == 0) { nearmisses += 1; return file; } @@ -1028,40 +979,34 @@ DirLookupSubdir(Path *p, const char *name) static char * DirLookupAbs(Path *p, const char *name, const char *cp) { - char *p1; /* pointer into p->name */ - const char *p2; /* pointer into name */ + char *p1; /* pointer into p->name */ + const char *p2; /* pointer into name */ - if (DEBUG(DIR)) { - fprintf(debug_file, " %s ...\n", p->name); - } + DIR_DEBUG1(" %s ...\n", p->name); - /* - * If the file has a leading path component and that component - * exactly matches the entire name of the current search - * directory, we can attempt another cache lookup. And if we don't - * have a hit, we can safely assume the file does not exist at all. - */ - for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) { - continue; - } - if (*p1 != '\0' || p2 != cp - 1) { - return NULL; - } + /* + * If the file has a leading path component and that component + * exactly matches the entire name of the current search + * directory, we can attempt another cache lookup. And if we don't + * have a hit, we can safely assume the file does not exist at all. + */ + for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) { + continue; + } + if (*p1 != '\0' || p2 != cp - 1) { + return NULL; + } - if (Hash_FindEntry(&p->files, cp) == NULL) { - if (DEBUG(DIR)) { - fprintf(debug_file, " must be here but isn't -- returning\n"); - } - /* Return empty string: terminates search */ - return bmake_strdup(""); - } + if (Hash_FindEntry(&p->files, cp) == NULL) { + DIR_DEBUG0(" must be here but isn't -- returning\n"); + /* Return empty string: terminates search */ + return bmake_strdup(""); + } - p->hits += 1; - hits += 1; - if (DEBUG(DIR)) { - fprintf(debug_file, " returning %s\n", name); - } - return bmake_strdup(name); + p->hits += 1; + hits += 1; + DIR_DEBUG1(" returning %s\n", name); + return bmake_strdup(name); } /*- @@ -1081,25 +1026,20 @@ static char * DirFindDot(Boolean hasSlash MAKE_ATTR_UNUSED, const char *name, const char *cp) { - if (Hash_FindEntry(&dot->files, cp) != NULL) { - if (DEBUG(DIR)) { - fprintf(debug_file, " in '.'\n"); - } - hits += 1; - dot->hits += 1; - return bmake_strdup(name); - } - if (cur && - Hash_FindEntry(&cur->files, cp) != NULL) { - if (DEBUG(DIR)) { - fprintf(debug_file, " in ${.CURDIR} = %s\n", cur->name); - } - hits += 1; - cur->hits += 1; - return str_concat(cur->name, cp, STR_ADDSLASH); - } + if (Hash_FindEntry(&dot->files, cp) != NULL) { + DIR_DEBUG0(" in '.'\n"); + hits += 1; + dot->hits += 1; + return bmake_strdup(name); + } + if (cur && Hash_FindEntry(&cur->files, cp) != NULL) { + DIR_DEBUG1(" in ${.CURDIR} = %s\n", cur->name); + hits += 1; + cur->hits += 1; + return str_concat3(cur->name, "/", cp); + } - return NULL; + return NULL; } /*- @@ -1127,14 +1067,14 @@ DirFindDot(Boolean hasSlash MAKE_ATTR_UNUSED, const char *name, const char *cp) char * Dir_FindFile(const char *name, Lst path) { - LstNode ln; /* a list element */ - char *file; /* the current filename to check */ - Path *p; /* current path member */ - const char *cp; /* Terminal name of file */ - Boolean hasLastDot = FALSE; /* true we should search dot last */ - Boolean hasSlash; /* true if 'name' contains a / */ - struct stat stb; /* Buffer for stat, if necessary */ - const char *trailing_dot = "."; + LstNode ln; /* a list element */ + char *file; /* the current filename to check */ + Path *p; /* current path member */ + const char *cp; /* Terminal name of file */ + Boolean hasLastDot = FALSE; /* true we should search dot last */ + Boolean hasSlash; /* true if 'name' contains a / */ + struct make_stat mst; /* Buffer for stat, if necessary */ + const char *trailing_dot = "."; /* * Find the final component of the name and note whether it has a @@ -1149,29 +1089,23 @@ Dir_FindFile(const char *name, Lst path) cp = name; } - if (DEBUG(DIR)) { - fprintf(debug_file, "Searching for %s ...", name); - } + DIR_DEBUG1("Searching for %s ...", name); - if (Lst_Open(path) == FAILURE) { - if (DEBUG(DIR)) { - fprintf(debug_file, "couldn't open path, file not found\n"); - } + if (path == NULL) { + DIR_DEBUG0("couldn't open path, file not found\n"); misses += 1; return NULL; } + Lst_Open(path); if ((ln = Lst_First(path)) != NULL) { - p = (Path *)Lst_Datum(ln); + p = LstNode_Datum(ln); if (p == dotLast) { hasLastDot = TRUE; - if (DEBUG(DIR)) - fprintf(debug_file, "[dot last]..."); + DIR_DEBUG0("[dot last]..."); } } - if (DEBUG(DIR)) { - fprintf(debug_file, "\n"); - } + DIR_DEBUG0("\n"); /* * If there's no leading directory components or if the leading @@ -1179,41 +1113,39 @@ Dir_FindFile(const char *name, Lst path) * of each of the directories on the search path. */ if (!hasSlash || (cp - name == 2 && *name == '.')) { - /* - * We look through all the directories on the path seeking one which - * contains the final component of the given name. If such a beast - * is found, we concatenate the directory name and the final - * component and return the resulting string. If we don't find any - * such thing, we go on to phase two... - * - * No matter what, we always look for the file in the current - * directory before anywhere else (unless we found the magic - * DOTLAST path, in which case we search it last) and we *do not* - * add the ./ to it if it exists. - * This is so there are no conflicts between what the user - * specifies (fish.c) and what pmake finds (./fish.c). - */ - if (!hasLastDot && - (file = DirFindDot(hasSlash, name, cp)) != NULL) { - Lst_Close(path); - return file; - } + /* + * We look through all the directories on the path seeking one which + * contains the final component of the given name. If such a beast + * is found, we concatenate the directory name and the final + * component and return the resulting string. If we don't find any + * such thing, we go on to phase two... + * + * No matter what, we always look for the file in the current + * directory before anywhere else (unless we found the magic + * DOTLAST path, in which case we search it last) and we *do not* + * add the ./ to it if it exists. + * This is so there are no conflicts between what the user + * specifies (fish.c) and what pmake finds (./fish.c). + */ + if (!hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) { + Lst_Close(path); + return file; + } - while ((ln = Lst_Next(path)) != NULL) { - p = (Path *)Lst_Datum(ln); - if (p == dotLast) - continue; - if ((file = DirLookup(p, name, cp, hasSlash)) != NULL) { - Lst_Close(path); - return file; - } + while ((ln = Lst_Next(path)) != NULL) { + p = LstNode_Datum(ln); + if (p == dotLast) + continue; + if ((file = DirLookup(p, name, cp, hasSlash)) != NULL) { + Lst_Close(path); + return file; } + } - if (hasLastDot && - (file = DirFindDot(hasSlash, name, cp)) != NULL) { - Lst_Close(path); - return file; - } + if (hasLastDot && (file = DirFindDot(hasSlash, name, cp)) != NULL) { + Lst_Close(path); + return file; + } } Lst_Close(path); @@ -1232,9 +1164,7 @@ Dir_FindFile(const char *name, Lst path) * This phase is only performed if the file is *not* absolute. */ if (!hasSlash) { - if (DEBUG(DIR)) { - fprintf(debug_file, " failed.\n"); - } + DIR_DEBUG0(" failed.\n"); misses += 1; return NULL; } @@ -1245,30 +1175,28 @@ Dir_FindFile(const char *name, Lst path) } if (name[0] != '/') { - Boolean checkedDot = FALSE; + Boolean checkedDot = FALSE; - if (DEBUG(DIR)) { - fprintf(debug_file, " Trying subdirectories...\n"); - } + DIR_DEBUG0(" Trying subdirectories...\n"); if (!hasLastDot) { - if (dot) { - checkedDot = TRUE; - if ((file = DirLookupSubdir(dot, name)) != NULL) - return file; - } - if (cur && (file = DirLookupSubdir(cur, name)) != NULL) - return file; + if (dot) { + checkedDot = TRUE; + if ((file = DirLookupSubdir(dot, name)) != NULL) + return file; + } + if (cur && (file = DirLookupSubdir(cur, name)) != NULL) + return file; } - (void)Lst_Open(path); + Lst_Open(path); while ((ln = Lst_Next(path)) != NULL) { - p = (Path *)Lst_Datum(ln); + p = LstNode_Datum(ln); if (p == dotLast) continue; if (p == dot) { - if (checkedDot) - continue; + if (checkedDot) + continue; checkedDot = TRUE; } if ((file = DirLookupSubdir(p, name)) != NULL) { @@ -1279,13 +1207,13 @@ Dir_FindFile(const char *name, Lst path) Lst_Close(path); if (hasLastDot) { - if (dot && !checkedDot) { - checkedDot = TRUE; - if ((file = DirLookupSubdir(dot, name)) != NULL) - return file; - } - if (cur && (file = DirLookupSubdir(cur, name)) != NULL) - return file; + if (dot && !checkedDot) { + checkedDot = TRUE; + if ((file = DirLookupSubdir(dot, name)) != NULL) + return file; + } + if (cur && (file = DirLookupSubdir(cur, name)) != NULL) + return file; } if (checkedDot) { @@ -1293,9 +1221,7 @@ Dir_FindFile(const char *name, Lst path) * Already checked by the given name, since . was in the path, * so no point in proceeding... */ - if (DEBUG(DIR)) { - fprintf(debug_file, " Checked . already, returning NULL\n"); - } + DIR_DEBUG0(" Checked . already, returning NULL\n"); return NULL; } @@ -1310,12 +1236,10 @@ Dir_FindFile(const char *name, Lst path) * file does not exist at all. This is signified by DirLookupAbs() * returning an empty string. */ - if (DEBUG(DIR)) { - fprintf(debug_file, " Trying exact path matches...\n"); - } + DIR_DEBUG0(" Trying exact path matches...\n"); - if (!hasLastDot && cur && ((file = DirLookupAbs(cur, name, cp)) - != NULL)) { + if (!hasLastDot && cur && + ((file = DirLookupAbs(cur, name, cp)) != NULL)) { if (file[0] == '\0') { free(file); return NULL; @@ -1323,9 +1247,9 @@ Dir_FindFile(const char *name, Lst path) return file; } - (void)Lst_Open(path); + Lst_Open(path); while ((ln = Lst_Next(path)) != NULL) { - p = (Path *)Lst_Datum(ln); + p = LstNode_Datum(ln); if (p == dotLast) continue; if ((file = DirLookupAbs(p, name, cp)) != NULL) { @@ -1339,8 +1263,8 @@ Dir_FindFile(const char *name, Lst path) } Lst_Close(path); - if (hasLastDot && cur && ((file = DirLookupAbs(cur, name, cp)) - != NULL)) { + if (hasLastDot && cur && + ((file = DirLookupAbs(cur, name, cp)) != NULL)) { if (file[0] == '\0') { free(file); return NULL; @@ -1380,7 +1304,7 @@ Dir_FindFile(const char *name, Lst path) if (ln == NULL) { return NULL; } else { - p = (Path *)Lst_Datum(ln); + p = LstNode_Datum(ln); } if (Hash_FindEntry(&p->files, cp) != NULL) { @@ -1389,18 +1313,14 @@ Dir_FindFile(const char *name, Lst path) return NULL; } #else /* !notdef */ - if (DEBUG(DIR)) { - fprintf(debug_file, " Looking for \"%s\" ...\n", name); - } + DIR_DEBUG1(" Looking for \"%s\" ...\n", name); bigmisses += 1; - if (cached_stat(name, &stb) == 0) { + if (cached_stat(name, &mst) == 0) { return bmake_strdup(name); } - if (DEBUG(DIR)) { - fprintf(debug_file, " failed. Returning NULL\n"); - } + DIR_DEBUG0(" failed. Returning NULL\n"); return NULL; #endif /* notdef */ } @@ -1416,7 +1336,7 @@ Dir_FindFile(const char *name, Lst path) * here starting directory * search_path the path we are looking for * result the result of a successful search is placed here - * rlen the length of the result buffer + * result_len the length of the result buffer * (typically MAXPATHLEN + 1) * * Results: @@ -1426,62 +1346,57 @@ Dir_FindFile(const char *name, Lst path) * Side Effects: *----------------------------------------------------------------------- */ -int -Dir_FindHereOrAbove(char *here, char *search_path, char *result, int rlen) { - - struct stat st; - char dirbase[MAXPATHLEN + 1], *db_end; - char try[MAXPATHLEN + 1], *try_end; - - /* copy out our starting point */ - snprintf(dirbase, sizeof(dirbase), "%s", here); - db_end = dirbase + strlen(dirbase); - - /* loop until we determine a result */ - while (1) { +Boolean +Dir_FindHereOrAbove(const char *here, const char *search_path, + char *result, int result_len) +{ + struct make_stat mst; + char dirbase[MAXPATHLEN + 1], *dirbase_end; + char try[MAXPATHLEN + 1], *try_end; - /* try and stat(2) it ... */ - snprintf(try, sizeof(try), "%s/%s", dirbase, search_path); - if (cached_stat(try, &st) != -1) { - /* - * success! if we found a file, chop off - * the filename so we return a directory. - */ - if ((st.st_mode & S_IFMT) != S_IFDIR) { - try_end = try + strlen(try); - while (try_end > try && *try_end != '/') - try_end--; - if (try_end > try) - *try_end = 0; /* chop! */ - } + /* copy out our starting point */ + snprintf(dirbase, sizeof(dirbase), "%s", here); + dirbase_end = dirbase + strlen(dirbase); - /* - * done! - */ - snprintf(result, rlen, "%s", try); - return 1; - } + /* loop until we determine a result */ + while (TRUE) { - /* - * nope, we didn't find it. if we used up dirbase we've - * reached the root and failed. - */ - if (db_end == dirbase) - break; /* failed! */ + /* try and stat(2) it ... */ + snprintf(try, sizeof(try), "%s/%s", dirbase, search_path); + if (cached_stat(try, &mst) != -1) { + /* + * success! if we found a file, chop off + * the filename so we return a directory. + */ + if ((mst.mst_mode & S_IFMT) != S_IFDIR) { + try_end = try + strlen(try); + while (try_end > try && *try_end != '/') + try_end--; + if (try_end > try) + *try_end = '\0'; /* chop! */ + } - /* - * truncate dirbase from the end to move up a dir - */ - while (db_end > dirbase && *db_end != '/') - db_end--; - *db_end = 0; /* chop! */ + snprintf(result, result_len, "%s", try); + return TRUE; + } - } /* while (1) */ + /* + * nope, we didn't find it. if we used up dirbase we've + * reached the root and failed. + */ + if (dirbase_end == dirbase) + break; /* failed! */ /* - * we failed... + * truncate dirbase from the end to move up a dir */ - return 0; + while (dirbase_end > dirbase && *dirbase_end != '/') + dirbase_end--; + *dirbase_end = '\0'; /* chop! */ + + } /* while (TRUE) */ + + return FALSE; } /*- @@ -1505,8 +1420,8 @@ Dir_FindHereOrAbove(char *here, char *search_path, char *result, int rlen) { int Dir_MTime(GNode *gn, Boolean recheck) { - char *fullName; /* the full pathname of name */ - struct stat stb; /* buffer for finding the mod time */ + char *fullName; /* the full pathname of name */ + struct make_stat mst; /* buffer for finding the mod time */ if (gn->type & OP_ARCHV) { return Arch_MTime(gn); @@ -1519,7 +1434,7 @@ Dir_MTime(GNode *gn, Boolean recheck) else { fullName = Dir_FindFile(gn->name, Suff_FindPath(gn)); if (fullName == NULL && gn->flags & FROM_DEPEND && - !Lst_IsEmpty(gn->iParents)) { + !Lst_IsEmpty(gn->implicitParents)) { char *cp; cp = strrchr(gn->name, '/'); @@ -1539,15 +1454,15 @@ Dir_MTime(GNode *gn, Boolean recheck) gn->path = bmake_strdup(fullName); if (!Job_RunTarget(".STALE", gn->fname)) fprintf(stdout, - "%s: %s, %d: ignoring stale %s for %s, " - "found %s\n", progname, gn->fname, gn->lineno, - makeDependfile, gn->name, fullName); + "%s: %s, %d: ignoring stale %s for %s, " + "found %s\n", progname, gn->fname, + gn->lineno, + makeDependfile, gn->name, fullName); } } } - if (DEBUG(DIR)) - fprintf(debug_file, "Found '%s' as '%s'\n", - gn->name, fullName ? fullName : "(not found)" ); + DIR_DEBUG2("Found '%s' as '%s'\n", + gn->name, fullName ? fullName : "(not found)"); } } else { fullName = gn->path; @@ -1557,13 +1472,13 @@ Dir_MTime(GNode *gn, Boolean recheck) fullName = bmake_strdup(gn->name); } - if (cached_stats(&mtimes, fullName, &stb, recheck ? CST_UPDATE : 0) < 0) { + if (cached_stats(&mtimes, fullName, &mst, recheck ? CST_UPDATE : 0) < 0) { if (gn->type & OP_MEMBER) { if (fullName != gn->path) free(fullName); return Arch_MemMTime(gn); } else { - stb.st_mtime = 0; + mst.mst_mtime = 0; } } @@ -1571,7 +1486,7 @@ Dir_MTime(GNode *gn, Boolean recheck) gn->path = fullName; } - gn->mtime = stb.st_mtime; + gn->mtime = mst.mst_mtime; return gn->mtime; } @@ -1585,6 +1500,8 @@ Dir_MTime(GNode *gn, Boolean recheck) * Input: * path the path to which the directory should be * added + * XXX: Why would this ever be NULL, and what does + * that mean? * name the name of the directory to add * * Results: @@ -1598,78 +1515,70 @@ Dir_MTime(GNode *gn, Boolean recheck) Path * Dir_AddDir(Lst path, const char *name) { - LstNode ln = NULL; /* node in case Path structure is found */ - Path *p = NULL; /* pointer to new Path structure */ - DIR *d; /* for reading directory */ - struct dirent *dp; /* entry in directory */ + LstNode ln = NULL; /* node in case Path structure is found */ + Path *p = NULL; /* pointer to new Path structure */ + DIR *d; /* for reading directory */ + struct dirent *dp; /* entry in directory */ - if (strcmp(name, ".DOTLAST") == 0) { - ln = Lst_Find(path, name, DirFindName); + if (path != NULL && strcmp(name, ".DOTLAST") == 0) { + ln = Lst_Find(path, DirFindName, name); if (ln != NULL) - return (Path *)Lst_Datum(ln); - else { - dotLast->refCount += 1; - (void)Lst_AtFront(path, dotLast); - } + return LstNode_Datum(ln); + + dotLast->refCount++; + Lst_Prepend(path, dotLast); } - if (path) - ln = Lst_Find(openDirectories, name, DirFindName); + if (path != NULL) + ln = Lst_Find(openDirectories, DirFindName, name); if (ln != NULL) { - p = (Path *)Lst_Datum(ln); - if (path && Lst_Member(path, p) == NULL) { + p = LstNode_Datum(ln); + if (Lst_FindDatum(path, p) == NULL) { p->refCount += 1; - (void)Lst_AtEnd(path, p); - } - } else { - if (DEBUG(DIR)) { - fprintf(debug_file, "Caching %s ...", name); + Lst_Append(path, p); } + return p; + } + + DIR_DEBUG1("Caching %s ...", name); - if ((d = opendir(name)) != NULL) { - p = bmake_malloc(sizeof(Path)); - p->name = bmake_strdup(name); - p->hits = 0; - p->refCount = 1; - Hash_InitTable(&p->files, -1); + if ((d = opendir(name)) != NULL) { + p = bmake_malloc(sizeof(Path)); + p->name = bmake_strdup(name); + p->hits = 0; + p->refCount = 1; + Hash_InitTable(&p->files, -1); - while ((dp = readdir(d)) != NULL) { + while ((dp = readdir(d)) != NULL) { #if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */ - /* - * The sun directory library doesn't check for a 0 inode - * (0-inode slots just take up space), so we have to do - * it ourselves. - */ - if (dp->d_fileno == 0) { - continue; - } -#endif /* sun && d_ino */ - (void)Hash_CreateEntry(&p->files, dp->d_name, NULL); + /* + * The sun directory library doesn't check for a 0 inode + * (0-inode slots just take up space), so we have to do + * it ourselves. + */ + if (dp->d_fileno == 0) { + continue; } - (void)closedir(d); - (void)Lst_AtEnd(openDirectories, p); - if (path != NULL) - (void)Lst_AtEnd(path, p); - } - if (DEBUG(DIR)) { - fprintf(debug_file, "done\n"); +#endif /* sun && d_ino */ + (void)Hash_CreateEntry(&p->files, dp->d_name, NULL); } + (void)closedir(d); + Lst_Append(openDirectories, p); + if (path != NULL) + Lst_Append(path, p); } + DIR_DEBUG0("done\n"); return p; } /*- *----------------------------------------------------------------------- * Dir_CopyDir -- - * Callback function for duplicating a search path via Lst_Duplicate. + * Callback function for duplicating a search path via Lst_Copy. * Ups the reference count for the directory. * * Results: * Returns the Path it was given. - * - * Side Effects: - * The refCount of the path is incremented. - * *----------------------------------------------------------------------- */ void * @@ -1704,25 +1613,23 @@ Dir_CopyDir(void *p) char * Dir_MakeFlags(const char *flag, Lst path) { - char *str; /* the string which will be returned */ - char *s1, *s2;/* the current directory preceded by 'flag' */ - LstNode ln; /* the node of the current directory */ - Path *p; /* the structure describing the current directory */ + Buffer buf; + LstNode ln; /* the node of the current directory */ - str = bmake_strdup(""); + Buf_Init(&buf, 0); - if (Lst_Open(path) == SUCCESS) { + if (path != NULL) { + Lst_Open(path); while ((ln = Lst_Next(path)) != NULL) { - p = (Path *)Lst_Datum(ln); - s2 = str_concat(flag, p->name, 0); - str = str_concat(s1 = str, s2, STR_ADDSPACE); - free(s1); - free(s2); + Path *p = LstNode_Datum(ln); + Buf_AddStr(&buf, " "); + Buf_AddStr(&buf, flag); + Buf_AddStr(&buf, p->name); } Lst_Close(path); } - return str; + return Buf_Destroy(&buf, FALSE); } /*- @@ -1746,14 +1653,14 @@ Dir_MakeFlags(const char *flag, Lst path) void Dir_Destroy(void *pp) { - Path *p = (Path *)pp; + Path *p = (Path *)pp; p->refCount -= 1; if (p->refCount == 0) { - LstNode ln; + LstNode ln; - ln = Lst_Member(openDirectories, p); - (void)Lst_Remove(openDirectories, ln); + ln = Lst_FindDatum(openDirectories, p); + Lst_Remove(openDirectories, ln); Hash_DeleteTable(&p->files); free(p->name); @@ -1781,9 +1688,8 @@ Dir_Destroy(void *pp) void Dir_ClearPath(Lst path) { - Path *p; while (!Lst_IsEmpty(path)) { - p = (Path *)Lst_DeQueue(path); + Path *p = Lst_Dequeue(path); Dir_Destroy(p); } } @@ -1811,37 +1717,43 @@ void Dir_Concat(Lst path1, Lst path2) { LstNode ln; - Path *p; + Path *p; - for (ln = Lst_First(path2); ln != NULL; ln = Lst_Succ(ln)) { - p = (Path *)Lst_Datum(ln); - if (Lst_Member(path1, p) == NULL) { + for (ln = Lst_First(path2); ln != NULL; ln = LstNode_Next(ln)) { + p = LstNode_Datum(ln); + if (Lst_FindDatum(path1, p) == NULL) { p->refCount += 1; - (void)Lst_AtEnd(path1, p); + Lst_Append(path1, p); } } } +static int +percentage(int num, int den) +{ + return den != 0 ? num * 100 / den : 0; +} + /********** DEBUG INFO **********/ void Dir_PrintDirectories(void) { - LstNode ln; - Path *p; + LstNode ln; fprintf(debug_file, "#*** Directory Cache:\n"); - fprintf(debug_file, "# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n", - hits, misses, nearmisses, bigmisses, - (hits+bigmisses+nearmisses ? - hits * 100 / (hits + bigmisses + nearmisses) : 0)); + fprintf(debug_file, + "# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n", + hits, misses, nearmisses, bigmisses, + percentage(hits, hits + bigmisses + nearmisses)); fprintf(debug_file, "# %-20s referenced\thits\n", "directory"); - if (Lst_Open(openDirectories) == SUCCESS) { - while ((ln = Lst_Next(openDirectories)) != NULL) { - p = (Path *)Lst_Datum(ln); - fprintf(debug_file, "# %-20s %10d\t%4d\n", p->name, p->refCount, p->hits); - } - Lst_Close(openDirectories); + + Lst_Open(openDirectories); + while ((ln = Lst_Next(openDirectories)) != NULL) { + Path *p = LstNode_Datum(ln); + fprintf(debug_file, "# %-20s %10d\t%4d\n", p->name, p->refCount, + p->hits); } + Lst_Close(openDirectories); } static int @@ -1,4 +1,4 @@ -/* $NetBSD: dir.h,v 1.18 2017/05/31 22:02:06 maya Exp $ */ +/* $NetBSD: dir.h,v 1.23 2020/09/02 04:08:54 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -72,29 +72,34 @@ * from: @(#)dir.h 8.1 (Berkeley) 6/6/93 */ -/* dir.h -- - */ - #ifndef MAKE_DIR_H #define MAKE_DIR_H -typedef struct Path { +/* A cache of a directory, remembering all the files that exist in that + * directory. */ +typedef struct { char *name; /* Name of directory */ int refCount; /* Number of paths with this directory */ int hits; /* the number of times a file in this * directory has been found */ - Hash_Table files; /* Hash table of files in directory */ + Hash_Table files; /* Hash set of files in directory */ } Path; -void Dir_Init(const char *); +struct make_stat { + time_t mst_mtime; + mode_t mst_mode; +}; + +void Dir_Init(void); +void Dir_InitDir(const char *); void Dir_InitCur(const char *); void Dir_InitDot(void); void Dir_End(void); void Dir_SetPATH(void); -Boolean Dir_HasWildcards(char *); +Boolean Dir_HasWildcards(const char *); void Dir_Expand(const char *, Lst, Lst); char *Dir_FindFile(const char *, Lst); -int Dir_FindHereOrAbove(char *, char *, char *, int); +Boolean Dir_FindHereOrAbove(const char *, const char *, char *, int); int Dir_MTime(GNode *, Boolean); Path *Dir_AddDir(Lst, const char *); char *Dir_MakeFlags(const char *, Lst); @@ -103,6 +108,9 @@ void Dir_Concat(Lst, Lst); void Dir_PrintDirectories(void); void Dir_PrintPath(Lst); void Dir_Destroy(void *); -void * Dir_CopyDir(void *); +void *Dir_CopyDir(void *); + +int cached_lstat(const char *, struct make_stat *); +int cached_stat(const char *, struct make_stat *); #endif /* MAKE_DIR_H */ diff --git a/enum.c b/enum.c new file mode 100755 index 000000000000..9dec4f3a5f6a --- /dev/null +++ b/enum.c @@ -0,0 +1,100 @@ +/* $NetBSD: enum.c,v 1.6 2020/09/01 20:34:51 rillig Exp $ */ + +/* + Copyright (c) 2020 Roland Illig <rillig@NetBSD.org> + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MAKE_NATIVE +static char rcsid[] = "$NetBSD: enum.c,v 1.6 2020/09/01 20:34:51 rillig Exp $"; +#else +#include <sys/cdefs.h> +#ifndef lint +__RCSID("$NetBSD: enum.c,v 1.6 2020/09/01 20:34:51 rillig Exp $"); +#endif +#endif + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "enum.h" + +/* Convert a bitset into a string representation, showing the names of the + * individual bits. + * + * Optionally, shortcuts for groups of bits can be added. To have an effect, + * they need to be listed before their individual bits. */ +const char * +Enum_FlagsToString(char *buf, size_t buf_size, + int value, const EnumToStringSpec *spec) +{ + const char *buf_start = buf; + const char *sep = ""; + size_t sep_len = 0; + + for (; spec->es_value != 0; spec++) { + size_t name_len; + + if ((value & spec->es_value) != spec->es_value) + continue; + value &= ~spec->es_value; + + assert(buf_size >= sep_len + 1); + memcpy(buf, sep, sep_len); + buf += sep_len; + buf_size -= sep_len; + + name_len = strlen(spec->es_name); + assert(buf_size >= name_len + 1); + memcpy(buf, spec->es_name, name_len); + buf += name_len; + buf_size -= name_len; + + sep = ENUM__SEP; + sep_len = sizeof ENUM__SEP - 1; + } + + /* If this assertion fails, the listed enum values are incomplete. */ + assert(value == 0); + + if (buf == buf_start) + return "none"; + + assert(buf_size >= 1); + buf[0] = '\0'; + return buf_start; +} + +/* Convert a fixed-value enum into a string representation. */ +const char * +Enum_ValueToString(int value, const EnumToStringSpec *spec) +{ + for (; spec->es_name[0] != '\0'; spec++) { + if (value == spec->es_value) + return spec->es_name; + } + abort(/* unknown enum value */); +} diff --git a/enum.h b/enum.h new file mode 100755 index 000000000000..d6a94f11e7cd --- /dev/null +++ b/enum.h @@ -0,0 +1,193 @@ +/* $NetBSD: enum.h,v 1.9 2020/09/01 20:34:51 rillig Exp $ */ + +/* + Copyright (c) 2020 Roland Illig <rillig@NetBSD.org> + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MAKE_ENUM_H +#define MAKE_ENUM_H + +/* Generate string representations for bitmasks and simple enums. */ + +#include <stddef.h> + +typedef struct { + int es_value; + const char *es_name; +} EnumToStringSpec; + +const char *Enum_FlagsToString(char *, size_t, int, const EnumToStringSpec *); +const char *Enum_ValueToString(int, const EnumToStringSpec *); + +/* For Enum_FlagsToString, the separator between flags. */ +#define ENUM__SEP "|" + +/* Generate the string that joins all possible flags, to see how large the + * buffer must be. */ +#define ENUM__JOIN_STR_1(v1) \ + #v1 +#define ENUM__JOIN_STR_2(v1, v2) \ + ENUM__JOIN_STR_1(v1) ENUM__SEP \ + ENUM__JOIN_STR_1(v2) +#define ENUM__JOIN_STR_4(v1, v2, v3, v4) \ + ENUM__JOIN_STR_2(v1, v2) ENUM__SEP \ + ENUM__JOIN_STR_2(v3, v4) +#define ENUM__JOIN_STR_8(v1, v2, v3, v4, v5, v6, v7, v8) \ + ENUM__JOIN_STR_4(v1, v2, v3, v4) ENUM__SEP \ + ENUM__JOIN_STR_4(v5, v6, v7, v8) +#define ENUM__JOIN_STR_16(v01, v02, v03, v04, v05, v06, v07, v08, \ + v09, v10, v11, v12, v13, v14, v15, v16) \ + ENUM__JOIN_STR_8(v01, v02, v03, v04, v05, v06, v07, v08) ENUM__SEP \ + ENUM__JOIN_STR_8(v09, v10, v11, v12, v13, v14, v15, v16) + +#define ENUM__JOIN_2(part1, part2) \ + part1 ENUM__SEP part2 +#define ENUM__JOIN_3(part1, part2, part3) \ + part1 ENUM__SEP part2 ENUM__SEP part3 +#define ENUM__JOIN_4(part1, part2, part3, part4) \ + part1 ENUM__SEP part2 ENUM__SEP part3 ENUM__SEP part4 +#define ENUM__JOIN_5(part1, part2, part3, part4, part5) \ + part1 ENUM__SEP part2 ENUM__SEP part3 ENUM__SEP part4 ENUM__SEP part5 + +/* List the pairs of enum value and corresponding name. */ +#define ENUM__SPEC_1(v1) \ + { v1, #v1 } +#define ENUM__SPEC_2(v1, v2) \ + ENUM__SPEC_1(v1), \ + ENUM__SPEC_1(v2) +#define ENUM__SPEC_4(v1, v2, v3, v4) \ + ENUM__SPEC_2(v1, v2), \ + ENUM__SPEC_2(v3, v4) +#define ENUM__SPEC_8(v1, v2, v3, v4, v5, v6, v7, v8) \ + ENUM__SPEC_4(v1, v2, v3, v4), \ + ENUM__SPEC_4(v5, v6, v7, v8) +#define ENUM__SPEC_16(v01, v02, v03, v04, v05, v06, v07, v08, \ + v09, v10, v11, v12, v13, v14, v15, v16) \ + ENUM__SPEC_8(v01, v02, v03, v04, v05, v06, v07, v08), \ + ENUM__SPEC_8(v09, v10, v11, v12, v13, v14, v15, v16) + +#define ENUM__SPECS_2(part1, part2) \ + { part1, part2, { 0, "" } } +#define ENUM__SPECS_3(part1, part2, part3) \ + { part1, part2, part3, { 0, "" } } +#define ENUM__SPECS_4(part1, part2, part3, part4) \ + { part1, part2, part3, part4, { 0, "" } } +#define ENUM__SPECS_5(part1, part2, part3, part4, part5) \ + { part1, part2, part3, part4, part5, { 0, "" } } + +/* Declare the necessary data structures for calling Enum_ValueToString. */ +#define ENUM__VALUE_RTTI(typnam, specs) \ + static const EnumToStringSpec typnam ## _ ## ToStringSpecs[] = specs + +/* Declare the necessary data structures for calling Enum_FlagsToString. */ +#define ENUM__FLAGS_RTTI(typnam, specs, joined) \ + static const EnumToStringSpec typnam ## _ ## ToStringSpecs[] = specs; \ + enum { typnam ## _ ## ToStringSize = sizeof joined } + +/* Declare the necessary data structures for calling Enum_FlagsToString + * for an enum with 3 flags. */ +#define ENUM_FLAGS_RTTI_3(typnam, v1, v2, v3) \ + ENUM__FLAGS_RTTI(typnam, \ + ENUM__SPECS_2( \ + ENUM__SPEC_2(v1, v2), \ + ENUM__SPEC_1(v3)), \ + ENUM__JOIN_2( \ + ENUM__JOIN_STR_2(v1, v2), \ + ENUM__JOIN_STR_1(v3))) + +/* Declare the necessary data structures for calling Enum_FlagsToString + * for an enum with 8 flags. */ +#define ENUM_FLAGS_RTTI_8(typnam, v1, v2, v3, v4, v5, v6, v7, v8) \ + ENUM__FLAGS_RTTI(typnam, \ + ENUM__SPECS_2( \ + ENUM__SPEC_4(v1, v2, v3, v4), \ + ENUM__SPEC_4(v5, v6, v7, v8)), \ + ENUM__JOIN_2( \ + ENUM__JOIN_STR_4(v1, v2, v3, v4), \ + ENUM__JOIN_STR_4(v5, v6, v7, v8))) + +/* Declare the necessary data structures for calling Enum_ValueToString + * for an enum with 8 constants. */ +#define ENUM_VALUE_RTTI_8(typnam, v1, v2, v3, v4, v5, v6, v7, v8) \ + ENUM__VALUE_RTTI(typnam, \ + ENUM__SPECS_2( \ + ENUM__SPEC_4(v1, v2, v3, v4), \ + ENUM__SPEC_4(v5, v6, v7, v8))) + +/* Declare the necessary data structures for calling Enum_FlagsToString + * for an enum with 10 flags. */ +#define ENUM_FLAGS_RTTI_10(typnam, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) \ + ENUM__FLAGS_RTTI(typnam, \ + ENUM__SPECS_2( \ + ENUM__SPEC_8(v1, v2, v3, v4, v5, v6, v7, v8), \ + ENUM__SPEC_2(v9, v10)), \ + ENUM__JOIN_2( \ + ENUM__JOIN_STR_8(v1, v2, v3, v4, v5, v6, v7, v8), \ + ENUM__JOIN_STR_2(v9, v10))) + +/* Declare the necessary data structures for calling Enum_FlagsToString + * for an enum with 31 flags. */ +#define ENUM_FLAGS_RTTI_31(typnam, \ + v01, v02, v03, v04, v05, v06, v07, v08, \ + v09, v10, v11, v12, v13, v14, v15, v16, \ + v17, v18, v19, v20, v21, v22, v23, v24, \ + v25, v26, v27, v28, v29, v30, v31) \ + ENUM__FLAGS_RTTI(typnam, \ + ENUM__SPECS_5( \ + ENUM__SPEC_16(v01, v02, v03, v04, v05, v06, v07, v08, \ + v09, v10, v11, v12, v13, v14, v15, v16), \ + ENUM__SPEC_8(v17, v18, v19, v20, v21, v22, v23, v24), \ + ENUM__SPEC_4(v25, v26, v27, v28), \ + ENUM__SPEC_2(v29, v30), \ + ENUM__SPEC_1(v31)), \ + ENUM__JOIN_5( \ + ENUM__JOIN_STR_16(v01, v02, v03, v04, v05, v06, v07, v08, \ + v09, v10, v11, v12, v13, v14, v15, v16), \ + ENUM__JOIN_STR_8(v17, v18, v19, v20, v21, v22, v23, v24), \ + ENUM__JOIN_STR_4(v25, v26, v27, v28), \ + ENUM__JOIN_STR_2(v29, v30), \ + ENUM__JOIN_STR_1(v31))) + +/* Declare the necessary data structures for calling Enum_FlagsToString + * for an enum with 32 flags. */ +#define ENUM_FLAGS_RTTI_32(typnam, \ + v01, v02, v03, v04, v05, v06, v07, v08, \ + v09, v10, v11, v12, v13, v14, v15, v16, \ + v17, v18, v19, v20, v21, v22, v23, v24, \ + v25, v26, v27, v28, v29, v30, v31, v32) \ + ENUM__FLAGS_RTTI(typnam, \ + ENUM__SPECS_2( \ + ENUM__SPEC_16(v01, v02, v03, v04, v05, v06, v07, v08, \ + v09, v10, v11, v12, v13, v14, v15, v16), \ + ENUM__SPEC_16(v17, v18, v19, v20, v21, v22, v23, v24, \ + v25, v26, v27, v28, v29, v30, v31, v32)), \ + ENUM__JOIN_2( \ + ENUM__JOIN_STR_16(v01, v02, v03, v04, v05, v06, v07, v08, \ + v09, v10, v11, v12, v13, v14, v15, v16), \ + ENUM__JOIN_STR_16(v17, v18, v19, v20, v21, v22, v23, v24, \ + v25, v26, v27, v28, v29, v30, v31, v32))) + +#endif @@ -1,4 +1,4 @@ -/* $NetBSD: for.c,v 1.54 2020/07/03 08:13:23 rillig Exp $ */ +/* $NetBSD: for.c,v 1.67 2020/08/30 19:56:02 rillig Exp $ */ /* * Copyright (c) 1992, The Regents of the University of California. @@ -30,14 +30,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: for.c,v 1.54 2020/07/03 08:13:23 rillig Exp $"; +static char rcsid[] = "$NetBSD: for.c,v 1.67 2020/08/30 19:56:02 rillig Exp $"; #else #include <sys/cdefs.h> #ifndef lint #if 0 static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93"; #else -__RCSID("$NetBSD: for.c,v 1.54 2020/07/03 08:13:23 rillig Exp $"); +__RCSID("$NetBSD: for.c,v 1.67 2020/08/30 19:56:02 rillig Exp $"); #endif #endif /* not lint */ #endif @@ -52,13 +52,7 @@ __RCSID("$NetBSD: for.c,v 1.54 2020/07/03 08:13:23 rillig Exp $"); * */ -#include <assert.h> -#include <ctype.h> - #include "make.h" -#include "hash.h" -#include "dir.h" -#include "buf.h" #include "strlist.h" #define FOR_SUB_ESCAPE_CHAR 1 @@ -83,34 +77,22 @@ __RCSID("$NetBSD: for.c,v 1.54 2020/07/03 08:13:23 rillig Exp $"); * For_Run. */ -static int forLevel = 0; /* Nesting level */ +static int forLevel = 0; /* Nesting level */ /* * State of a for loop. */ -typedef struct _For { - Buffer buf; /* Body of loop */ - strlist_t vars; /* Iteration variables */ - strlist_t items; /* Substitution items */ - char *parse_buf; - int short_var; - int sub_next; +typedef struct { + Buffer buf; /* Body of loop */ + strlist_t vars; /* Iteration variables */ + strlist_t items; /* Substitution items */ + char *parse_buf; + int short_var; + int sub_next; } For; -static For *accumFor; /* Loop being accumulated */ - - - -static char * -make_str(const char *ptr, int len) -{ - char *new_ptr; +static For *accumFor; /* Loop being accumulated */ - new_ptr = bmake_malloc(len + 1); - memcpy(new_ptr, ptr, len); - new_ptr[len] = 0; - return new_ptr; -} static void For_Free(For *arg) @@ -148,14 +130,13 @@ For_Eval(char *line) { For *new_for; char *ptr = line, *sub; - int len; + size_t len; int escapes; unsigned char ch; - char **words, *word_buf; - int n, nwords; + Words words; /* Skip the '.' and any following whitespace */ - for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++) + for (ptr++; *ptr && isspace((unsigned char)*ptr); ptr++) continue; /* @@ -163,8 +144,8 @@ For_Eval(char *line) * a for. */ if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' || - !isspace((unsigned char) ptr[3])) { - if (ptr[0] == 'e' && strncmp(ptr+1, "ndfor", 5) == 0) { + !isspace((unsigned char)ptr[3])) { + if (ptr[0] == 'e' && strncmp(ptr + 1, "ndfor", 5) == 0) { Parse_Error(PARSE_FATAL, "for-less endfor"); return -1; } @@ -181,7 +162,7 @@ For_Eval(char *line) /* Grab the variables. Terminate on "in". */ for (;; ptr += len) { - while (*ptr && isspace((unsigned char) *ptr)) + while (*ptr && isspace((unsigned char)*ptr)) ptr++; if (*ptr == '\0') { Parse_Error(PARSE_FATAL, "missing `in' in for"); @@ -196,7 +177,7 @@ For_Eval(char *line) } if (len == 1) new_for->short_var = 1; - strlist_add_str(&new_for->vars, make_str(ptr, len), len); + strlist_add_str(&new_for->vars, bmake_strldup(ptr, len), len); } if (strlist_num(&new_for->vars) == 0) { @@ -205,7 +186,7 @@ For_Eval(char *line) return -1; } - while (*ptr && isspace((unsigned char) *ptr)) + while (*ptr && isspace((unsigned char)*ptr)) ptr++; /* @@ -216,23 +197,25 @@ For_Eval(char *line) * We can't do the escapes here - because we don't know whether * we are substuting into ${...} or $(...). */ - sub = Var_Subst(NULL, ptr, VAR_GLOBAL, VARF_WANTRES); + sub = Var_Subst(ptr, VAR_GLOBAL, VARE_WANTRES); /* * Split into words allowing for quoted strings. */ - words = brk_string(sub, &nwords, FALSE, &word_buf); + words = Str_Words(sub, FALSE); free(sub); - if (words != NULL) { - for (n = 0; n < nwords; n++) { - ptr = words[n]; + { + size_t n; + + for (n = 0; n < words.len; n++) { + ptr = words.words[n]; if (!*ptr) continue; escapes = 0; while ((ch = *ptr++)) { - switch(ch) { + switch (ch) { case ':': case '$': case '\\': @@ -250,17 +233,17 @@ For_Eval(char *line) * We have to dup words[n] to maintain the semantics of * strlist. */ - strlist_add_str(&new_for->items, bmake_strdup(words[n]), escapes); + strlist_add_str(&new_for->items, bmake_strdup(words.words[n]), + escapes); } - free(words); - free(word_buf); + Words_Free(words); if ((len = strlist_num(&new_for->items)) > 0 && len % (n = strlist_num(&new_for->vars))) { Parse_Error(PARSE_FATAL, - "Wrong number of words (%d) in .for substitution list" - " with %d vars", len, n); + "Wrong number of words (%zu) in .for substitution list" + " with %zu vars", len, n); /* * Return 'success' so that the body of the .for loop is * accumulated. @@ -288,49 +271,35 @@ For_Accum(char *line) if (*ptr == '.') { - for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++) + for (ptr++; *ptr && isspace((unsigned char)*ptr); ptr++) continue; if (strncmp(ptr, "endfor", 6) == 0 && - (isspace((unsigned char) ptr[6]) || !ptr[6])) { + (isspace((unsigned char)ptr[6]) || !ptr[6])) { if (DEBUG(FOR)) (void)fprintf(debug_file, "For: end for %d\n", forLevel); if (--forLevel <= 0) return 0; } else if (strncmp(ptr, "for", 3) == 0 && - isspace((unsigned char) ptr[3])) { + isspace((unsigned char)ptr[3])) { forLevel++; if (DEBUG(FOR)) (void)fprintf(debug_file, "For: new loop %d\n", forLevel); } } - Buf_AddBytes(&accumFor->buf, strlen(line), line); + Buf_AddStr(&accumFor->buf, line); Buf_AddByte(&accumFor->buf, '\n'); return 1; } - -/*- - *----------------------------------------------------------------------- - * For_Run -- - * Run the for loop, imitating the actions of an include file - * - * Results: - * None. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -static int +static size_t for_var_len(const char *var) { char ch, var_start, var_end; int depth; - int len; + size_t len; var_start = *var; if (var_start == 0) @@ -360,24 +329,24 @@ for_var_len(const char *var) static void for_substitute(Buffer *cmds, strlist_t *items, unsigned int item_no, char ech) { - const char *item = strlist_str(items, item_no); - int len; char ch; + const char *item = strlist_str(items, item_no); + /* If there were no escapes, or the only escape is the other variable * terminator, then just substitute the full string */ if (!(strlist_info(items, item_no) & - (ech == ')' ? ~FOR_SUB_ESCAPE_BRACE : ~FOR_SUB_ESCAPE_PAREN))) { - Buf_AddBytes(cmds, strlen(item), item); + (ech == ')' ? ~FOR_SUB_ESCAPE_BRACE : ~FOR_SUB_ESCAPE_PAREN))) { + Buf_AddStr(cmds, item); return; } /* Escape ':', '$', '\\' and 'ech' - removed by :U processing */ while ((ch = *item++) != 0) { if (ch == '$') { - len = for_var_len(item); + size_t len = for_var_len(item); if (len != 0) { - Buf_AddBytes(cmds, len + 1, item - 1); + Buf_AddBytes(cmds, item - 1, len + 1); item += len; continue; } @@ -392,13 +361,14 @@ static char * For_Iterate(void *v_arg, size_t *ret_len) { For *arg = v_arg; - int i, len; + int i; char *var; char *cp; char *cmd_cp; char *body_end; char ch; Buffer cmds; + size_t cmd_len; if (arg->sub_next + strlist_num(&arg->vars) > strlist_num(&arg->items)) { /* No more iterations */ @@ -421,9 +391,9 @@ For_Iterate(void *v_arg, size_t *ret_len) * to contrive a makefile where an unwanted substitution happens. */ - cmd_cp = Buf_GetAll(&arg->buf, &len); - body_end = cmd_cp + len; - Buf_Init(&cmds, len + 256); + cmd_cp = Buf_GetAll(&arg->buf, &cmd_len); + body_end = cmd_cp + cmd_len; + Buf_Init(&cmds, cmd_len + 256); for (cp = cmd_cp; (cp = strchr(cp, '$')) != NULL;) { char ech; ch = *++cp; @@ -431,15 +401,15 @@ For_Iterate(void *v_arg, size_t *ret_len) cp++; /* Check variable name against the .for loop variables */ STRLIST_FOREACH(var, &arg->vars, i) { - len = strlist_info(&arg->vars, i); - if (memcmp(cp, var, len) != 0) + size_t vlen = strlist_info(&arg->vars, i); + if (memcmp(cp, var, vlen) != 0) continue; - if (cp[len] != ':' && cp[len] != ech && cp[len] != '\\') + if (cp[vlen] != ':' && cp[vlen] != ech && cp[vlen] != '\\') continue; /* Found a variable match. Replace with :U<value> */ - Buf_AddBytes(&cmds, cp - cmd_cp, cmd_cp); - Buf_AddBytes(&cmds, 2, ":U"); - cp += len; + Buf_AddBytesBetween(&cmds, cmd_cp, cp); + Buf_AddStr(&cmds, ":U"); + cp += vlen; cmd_cp = cp; for_substitute(&cmds, &arg->items, arg->sub_next + i, ech); break; @@ -457,15 +427,15 @@ For_Iterate(void *v_arg, size_t *ret_len) if (var[0] != ch || var[1] != 0) continue; /* Found a variable match. Replace with ${:U<value>} */ - Buf_AddBytes(&cmds, cp - cmd_cp, cmd_cp); - Buf_AddBytes(&cmds, 3, "{:U"); + Buf_AddBytesBetween(&cmds, cmd_cp, cp); + Buf_AddStr(&cmds, "{:U"); cmd_cp = ++cp; for_substitute(&cmds, &arg->items, arg->sub_next + i, /*{*/ '}'); - Buf_AddBytes(&cmds, 1, "}"); + Buf_AddByte(&cmds, '}'); break; } } - Buf_AddBytes(&cmds, body_end - cmd_cp, cmd_cp); + Buf_AddBytesBetween(&cmds, cmd_cp, body_end); cp = Buf_Destroy(&cmds, FALSE); if (DEBUG(FOR)) @@ -478,6 +448,7 @@ For_Iterate(void *v_arg, size_t *ret_len) return cp; } +/* Run the for loop, imitating the actions of an include file. */ void For_Run(int lineno) { @@ -487,9 +458,9 @@ For_Run(int lineno) accumFor = NULL; if (strlist_num(&arg->items) == 0) { - /* Nothing to expand - possibly due to an earlier syntax error. */ - For_Free(arg); - return; + /* Nothing to expand - possibly due to an earlier syntax error. */ + For_Free(arg); + return; } Parse_SetInput(NULL, lineno, -1, For_Iterate, arg); @@ -1,4 +1,4 @@ -/* $NetBSD: hash.c,v 1.22 2020/07/03 17:03:09 rillig Exp $ */ +/* $NetBSD: hash.c,v 1.29 2020/09/01 21:11:31 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -70,14 +70,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: hash.c,v 1.22 2020/07/03 17:03:09 rillig Exp $"; +static char rcsid[] = "$NetBSD: hash.c,v 1.29 2020/09/01 21:11:31 rillig Exp $"; #else #include <sys/cdefs.h> #ifndef lint #if 0 static char sccsid[] = "@(#)hash.c 8.1 (Berkeley) 6/6/93"; #else -__RCSID("$NetBSD: hash.c,v 1.22 2020/07/03 17:03:09 rillig Exp $"); +__RCSID("$NetBSD: hash.c,v 1.29 2020/09/01 21:11:31 rillig Exp $"); #endif #endif /* not lint */ #endif @@ -89,9 +89,7 @@ __RCSID("$NetBSD: hash.c,v 1.22 2020/07/03 17:03:09 rillig Exp $"); * table. Hash tables grow automatically as the amount of * information increases. */ -#include "sprite.h" #include "make.h" -#include "hash.h" /* * Forward references to local procedures that are used before they're @@ -107,29 +105,26 @@ static void RebuildTable(Hash_Table *); #define rebuildLimit 3 -/* - *--------------------------------------------------------- - * - * Hash_InitTable -- - * - * This routine just sets up the hash table. +/* The hash function(s) */ + +#ifndef HASH +/* The default: this one matches Gosling's emacs */ +#define HASH(h, key, p) do { \ + for (h = 0, p = key; *p;) \ + h = (h << 5) - h + *p++; \ + } while (0) + +#endif + +/* Sets up the hash table. * * Input: - * t Structure to to hold table. + * t Structure to to hold the table. * numBuckets How many buckets to create for starters. This * number is rounded up to a power of two. If * <= 0, a reasonable default is chosen. The * table will grow in size later as needed. - * - * Results: - * None. - * - * Side Effects: - * Memory is allocated for the initial bucket area. - * - *--------------------------------------------------------- */ - void Hash_InitTable(Hash_Table *t, int numBuckets) { @@ -146,118 +141,85 @@ Hash_InitTable(Hash_Table *t, int numBuckets) continue; } t->numEntries = 0; - t->size = i; - t->mask = i - 1; - t->bucketPtr = hp = bmake_malloc(sizeof(*hp) * i); + t->maxchain = 0; + t->bucketsSize = i; + t->bucketsMask = i - 1; + t->buckets = hp = bmake_malloc(sizeof(*hp) * i); while (--i >= 0) *hp++ = NULL; } -/* - *--------------------------------------------------------- - * - * Hash_DeleteTable -- - * - * This routine removes everything from a hash table - * and frees up the memory space it occupied (except for - * the space in the Hash_Table structure). - * - * Results: - * None. - * - * Side Effects: - * Lots of memory is freed up. - * - *--------------------------------------------------------- - */ - +/* Removes everything from the hash table and frees up the memory space it + * occupied (except for the space in the Hash_Table structure). */ void Hash_DeleteTable(Hash_Table *t) { struct Hash_Entry **hp, *h, *nexth = NULL; int i; - for (hp = t->bucketPtr, i = t->size; --i >= 0;) { + for (hp = t->buckets, i = t->bucketsSize; --i >= 0;) { for (h = *hp++; h != NULL; h = nexth) { nexth = h->next; free(h); } } - free(t->bucketPtr); + free(t->buckets); /* * Set up the hash table to cause memory faults on any future access * attempts until re-initialization. */ - t->bucketPtr = NULL; + t->buckets = NULL; } -/* - *--------------------------------------------------------- - * - * Hash_FindEntry -- - * - * Searches a hash table for an entry corresponding to key. +/* Searches the hash table for an entry corresponding to the key. * * Input: * t Hash table to search. * key A hash key. * * Results: - * The return value is a pointer to the entry for key, - * if key was present in the table. If key was not - * present, NULL is returned. - * - * Side Effects: - * None. - * - *--------------------------------------------------------- + * Returns a pointer to the entry for key, or NULL if the table contains + * no entry for the key. */ - Hash_Entry * Hash_FindEntry(Hash_Table *t, const char *key) { Hash_Entry *e; unsigned h; const char *p; + int chainlen; - if (t == NULL || t->bucketPtr == NULL) { + if (t == NULL || t->buckets == NULL) { return NULL; } - for (h = 0, p = key; *p;) - h = (h << 5) - h + *p++; + HASH(h, key, p); p = key; - for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) + chainlen = 0; +#ifdef DEBUG_HASH_LOOKUP + if (DEBUG(HASH)) + fprintf(debug_file, "%s: %p h=%x key=%s\n", __func__, + t, h, key); +#endif + for (e = t->buckets[h & t->bucketsMask]; e != NULL; e = e->next) { + chainlen++; if (e->namehash == h && strcmp(e->name, p) == 0) - return e; - return NULL; + break; + } + if (chainlen > t->maxchain) + t->maxchain = chainlen; + return e; } -/* - *--------------------------------------------------------- - * - * Hash_CreateEntry -- - * - * Searches a hash table for an entry corresponding to - * key. If no entry is found, then one is created. +/* Searches the hash table for an entry corresponding to the key. + * If no entry is found, then one is created. * * Input: * t Hash table to search. * key A hash key. - * newPtr Filled in with TRUE if new entry created, + * newPtr Filled with TRUE if new entry created, * FALSE otherwise. - * - * Results: - * The return value is a pointer to the entry. If *newPtr - * isn't NULL, then *newPtr is filled in with TRUE if a - * new entry was created, and FALSE if an entry already existed - * with the given key. - * - * Side Effects: - * Memory may be allocated, and the hash buckets may be modified. - *--------------------------------------------------------- */ - Hash_Entry * Hash_CreateEntry(Hash_Table *t, const char *key, Boolean *newPtr) { @@ -265,33 +227,44 @@ Hash_CreateEntry(Hash_Table *t, const char *key, Boolean *newPtr) unsigned h; const char *p; int keylen; + int chainlen; struct Hash_Entry **hp; /* * Hash the key. As a side effect, save the length (strlen) of the * key in case we need to create the entry. */ - for (h = 0, p = key; *p;) - h = (h << 5) - h + *p++; + HASH(h, key, p); keylen = p - key; p = key; - for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) { + chainlen = 0; +#ifdef DEBUG_HASH_LOOKUP + if (DEBUG(HASH)) + fprintf(debug_file, "%s: %p h=%x key=%s\n", __func__, + t, h, key); +#endif + for (e = t->buckets[h & t->bucketsMask]; e != NULL; e = e->next) { + chainlen++; if (e->namehash == h && strcmp(e->name, p) == 0) { if (newPtr != NULL) *newPtr = FALSE; - return e; + break; } } + if (chainlen > t->maxchain) + t->maxchain = chainlen; + if (e) + return e; /* * The desired entry isn't there. Before allocating a new entry, * expand the table if necessary (and this changes the resulting * bucket chain). */ - if (t->numEntries >= rebuildLimit * t->size) + if (t->numEntries >= rebuildLimit * t->bucketsSize) RebuildTable(t); e = bmake_malloc(sizeof(*e) + keylen); - hp = &t->bucketPtr[h & t->mask]; + hp = &t->buckets[h & t->bucketsMask]; e->next = *hp; *hp = e; Hash_SetValue(e, NULL); @@ -304,23 +277,7 @@ Hash_CreateEntry(Hash_Table *t, const char *key, Boolean *newPtr) return e; } -/* - *--------------------------------------------------------- - * - * Hash_DeleteEntry -- - * - * Delete the given hash table entry and free memory associated with - * it. - * - * Results: - * None. - * - * Side Effects: - * Hash chain that entry lives in is modified and memory is freed. - * - *--------------------------------------------------------- - */ - +/* Delete the given hash table entry and free memory associated with it. */ void Hash_DeleteEntry(Hash_Table *t, Hash_Entry *e) { @@ -328,7 +285,7 @@ Hash_DeleteEntry(Hash_Table *t, Hash_Entry *e) if (e == NULL) return; - for (hp = &t->bucketPtr[e->namehash & t->mask]; + for (hp = &t->buckets[e->namehash & t->bucketsMask]; (p = *hp) != NULL; hp = &p->next) { if (p == e) { *hp = p->next; @@ -341,12 +298,7 @@ Hash_DeleteEntry(Hash_Table *t, Hash_Entry *e) abort(); } -/* - *--------------------------------------------------------- - * - * Hash_EnumFirst -- - * This procedure sets things up for a complete search - * of all entries recorded in the hash table. +/* Sets things up for enumerating all entries in the hash table. * * Input: * t Table to be searched. @@ -355,57 +307,34 @@ Hash_DeleteEntry(Hash_Table *t, Hash_Entry *e) * Results: * The return value is the address of the first entry in * the hash table, or NULL if the table is empty. - * - * Side Effects: - * The information in searchPtr is initialized so that successive - * calls to Hash_Next will return successive HashEntry's - * from the table. - * - *--------------------------------------------------------- */ - Hash_Entry * Hash_EnumFirst(Hash_Table *t, Hash_Search *searchPtr) { - searchPtr->tablePtr = t; - searchPtr->nextIndex = 0; - searchPtr->hashEntryPtr = NULL; + searchPtr->table = t; + searchPtr->nextBucket = 0; + searchPtr->entry = NULL; return Hash_EnumNext(searchPtr); } -/* - *--------------------------------------------------------- - * - * Hash_EnumNext -- - * This procedure returns successive entries in the hash table. +/* Returns the next entry in the hash table, or NULL if the end of the table + * is reached. * * Input: * searchPtr Area used to keep state about search. - * - * Results: - * The return value is a pointer to the next HashEntry - * in the table, or NULL when the end of the table is - * reached. - * - * Side Effects: - * The information in searchPtr is modified to advance to the - * next entry. - * - *--------------------------------------------------------- */ - Hash_Entry * Hash_EnumNext(Hash_Search *searchPtr) { Hash_Entry *e; - Hash_Table *t = searchPtr->tablePtr; + Hash_Table *t = searchPtr->table; /* - * The hashEntryPtr field points to the most recently returned - * entry, or is nil if we are starting up. If not nil, we have + * The entry field points to the most recently returned + * entry, or is NULL if we are starting up. If not NULL, we have * to start at the next one in the chain. */ - e = searchPtr->hashEntryPtr; + e = searchPtr->entry; if (e != NULL) e = e->next; /* @@ -413,59 +342,49 @@ Hash_EnumNext(Hash_Search *searchPtr) * find the next nonempty chain. */ while (e == NULL) { - if (searchPtr->nextIndex >= t->size) + if (searchPtr->nextBucket >= t->bucketsSize) return NULL; - e = t->bucketPtr[searchPtr->nextIndex++]; + e = t->buckets[searchPtr->nextBucket++]; } - searchPtr->hashEntryPtr = e; + searchPtr->entry = e; return e; } -/* - *--------------------------------------------------------- - * - * RebuildTable -- - * This local routine makes a new hash table that - * is larger than the old one. - * - * Results: - * None. - * - * Side Effects: - * The entire hash table is moved, so any bucket numbers - * from the old table are invalid. - * - *--------------------------------------------------------- - */ - +/* Makes a new hash table that is larger than the old one. The entire hash + * table is moved, so any bucket numbers from the old table become invalid. */ static void RebuildTable(Hash_Table *t) { Hash_Entry *e, *next = NULL, **hp, **xp; int i, mask; - Hash_Entry **oldhp; + Hash_Entry **oldhp; int oldsize; - oldhp = t->bucketPtr; - oldsize = i = t->size; + oldhp = t->buckets; + oldsize = i = t->bucketsSize; i <<= 1; - t->size = i; - t->mask = mask = i - 1; - t->bucketPtr = hp = bmake_malloc(sizeof(*hp) * i); + t->bucketsSize = i; + t->bucketsMask = mask = i - 1; + t->buckets = hp = bmake_malloc(sizeof(*hp) * i); while (--i >= 0) *hp++ = NULL; for (hp = oldhp, i = oldsize; --i >= 0;) { for (e = *hp++; e != NULL; e = next) { next = e->next; - xp = &t->bucketPtr[e->namehash & mask]; + xp = &t->buckets[e->namehash & mask]; e->next = *xp; *xp = e; } } free(oldhp); + if (DEBUG(HASH)) + fprintf(debug_file, "%s: %p size=%d entries=%d maxchain=%d\n", + __func__, t, t->bucketsSize, t->numEntries, t->maxchain); + t->maxchain = 0; } -void Hash_ForEach(Hash_Table *t, void (*action)(void *, void *), void *data) +void +Hash_ForEach(Hash_Table *t, void (*action)(void *, void *), void *data) { Hash_Search search; Hash_Entry *e; @@ -475,3 +394,11 @@ void Hash_ForEach(Hash_Table *t, void (*action)(void *, void *), void *data) e = Hash_EnumNext(&search)) action(Hash_GetValue(e), data); } + +void +Hash_DebugStats(Hash_Table *t, const char *name) +{ + if (DEBUG(HASH)) + fprintf(debug_file, "Hash_Table %s: size=%d numEntries=%d maxchain=%d\n", + name, t->bucketsSize, t->numEntries, t->maxchain); +} @@ -1,4 +1,4 @@ -/* $NetBSD: hash.h,v 1.13 2020/07/03 17:03:09 rillig Exp $ */ +/* $NetBSD: hash.h,v 1.21 2020/09/01 21:11:31 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -72,71 +72,51 @@ * from: @(#)hash.h 8.1 (Berkeley) 6/6/93 */ -/* hash.h -- - * - * This file contains definitions used by the hash module, - * which maintains hash tables. - */ - -#ifndef _HASH_H -#define _HASH_H +/* Hash tables with strings as keys and arbitrary pointers as values. */ -/* - * The following defines one entry in the hash table. - */ +#ifndef MAKE_HASH_H +#define MAKE_HASH_H +/* A single key-value entry in the hash table. */ typedef struct Hash_Entry { - struct Hash_Entry *next; /* Used to link together all the - * entries associated with the same - * bucket. */ - void *clientPtr; /* Arbitrary pointer */ - unsigned namehash; /* hash value of key */ - char name[1]; /* key string */ + struct Hash_Entry *next; /* Used to link together all the entries + * associated with the same bucket. */ + void *value; + unsigned namehash; /* hash value of key */ + char name[1]; /* key string, variable length */ } Hash_Entry; +/* The hash table containing the entries. */ typedef struct Hash_Table { - struct Hash_Entry **bucketPtr;/* Pointers to Hash_Entry, one - * for each bucket in the table. */ - int size; /* Actual size of array. */ + Hash_Entry **buckets; /* Pointers to Hash_Entry, one + * for each bucket in the table. */ + int bucketsSize; int numEntries; /* Number of entries in the table. */ - int mask; /* Used to select bits for hashing. */ + int bucketsMask; /* Used to select the bucket for a hash. */ + int maxchain; /* max length of chain detected */ } Hash_Table; /* * The following structure is used by the searching routines * to record where we are in the search. */ - typedef struct Hash_Search { - Hash_Table *tablePtr; /* Table being searched. */ - int nextIndex; /* Next bucket to check (after current). */ - Hash_Entry *hashEntryPtr; /* Next entry to check in current bucket. */ + Hash_Table *table; /* Table being searched. */ + int nextBucket; /* Next bucket to check (after current). */ + Hash_Entry *entry; /* Next entry to check in current bucket. */ } Hash_Search; -/* - * Macros. - */ - -/* - * void * Hash_GetValue(h) - * Hash_Entry *h; - */ - -#define Hash_GetValue(h) ((h)->clientPtr) - -/* - * Hash_SetValue(h, val); - * Hash_Entry *h; - * char *val; - */ - -#define Hash_SetValue(h, val) ((h)->clientPtr = (val)) - -/* - * Hash_Size(n) returns the number of words in an object of n bytes - */ +static inline void * MAKE_ATTR_UNUSED +Hash_GetValue(Hash_Entry *h) +{ + return h->value; +} -#define Hash_Size(n) (((n) + sizeof (int) - 1) / sizeof (int)) +static inline void MAKE_ATTR_UNUSED +Hash_SetValue(Hash_Entry *h, void *datum) +{ + h->value = datum; +} void Hash_InitTable(Hash_Table *, int); void Hash_DeleteTable(Hash_Table *); @@ -146,5 +126,6 @@ void Hash_DeleteEntry(Hash_Table *, Hash_Entry *); Hash_Entry *Hash_EnumFirst(Hash_Table *, Hash_Search *); Hash_Entry *Hash_EnumNext(Hash_Search *); void Hash_ForEach(Hash_Table *, void (*)(void *, void *), void *); +void Hash_DebugStats(Hash_Table *, const char *); -#endif /* _HASH_H */ +#endif /* MAKE_HASH_H */ @@ -1,4 +1,4 @@ -/* $NetBSD: job.c,v 1.201 2020/07/03 08:13:23 rillig Exp $ */ +/* $NetBSD: job.c,v 1.227 2020/08/30 19:56:02 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -70,14 +70,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: job.c,v 1.201 2020/07/03 08:13:23 rillig Exp $"; +static char rcsid[] = "$NetBSD: job.c,v 1.227 2020/08/30 19:56:02 rillig Exp $"; #else #include <sys/cdefs.h> #ifndef lint #if 0 static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94"; #else -__RCSID("$NetBSD: job.c,v 1.201 2020/07/03 08:13:23 rillig Exp $"); +__RCSID("$NetBSD: job.c,v 1.227 2020/08/30 19:56:02 rillig Exp $"); #endif #endif /* not lint */ #endif @@ -112,7 +112,7 @@ __RCSID("$NetBSD: job.c,v 1.201 2020/07/03 08:13:23 rillig Exp $"); * * Job_ParseShell Given the line following a .SHELL target, parse * the line as a shell specification. Returns - * FAILURE if the spec was incorrect. + * FALSE if the spec was incorrect. * * Job_Finish Perform any final processing which needs doing. * This includes the execution of any commands @@ -142,7 +142,6 @@ __RCSID("$NetBSD: job.c,v 1.201 2020/07/03 08:13:23 rillig Exp $"); #include <sys/time.h> #include "wait.h" -#include <assert.h> #include <errno.h> #if !defined(USE_SELECT) && defined(HAVE_POLL_H) #include <poll.h> @@ -155,15 +154,12 @@ __RCSID("$NetBSD: job.c,v 1.201 2020/07/03 08:13:23 rillig Exp $"); #endif #endif #include <signal.h> -#include <stdio.h> -#include <string.h> #include <utime.h> #if defined(HAVE_SYS_SOCKET_H) # include <sys/socket.h> #endif #include "make.h" -#include "hash.h" #include "dir.h" #include "job.h" #include "pathnames.h" @@ -184,7 +180,6 @@ static int aborting = 0; /* why is the make aborting? */ * this tracks the number of tokens currently "out" to build jobs. */ int jobTokensRunning = 0; -int not_parallel = 0; /* set if .NOT_PARALLEL */ /* * XXX: Avoid SunOS bug... FILENO() is fp->_file, and file @@ -311,9 +306,9 @@ static Shell *commandShell = &shells[DEFSHELL_INDEX]; /* this is the shell to * Job_ParseShell function */ const char *shellPath = NULL, /* full pathname of * executable image */ - *shellName = NULL; /* last component of shell */ + *shellName = NULL; /* last component of shell */ char *shellErrFlag = NULL; -static const char *shellArgv = NULL; /* Custom shell args */ +static char *shellArgv = NULL; /* Custom shell args */ STATIC Job *job_table; /* The structures that describe them */ @@ -370,11 +365,6 @@ static void JobSigLock(sigset_t *); static void JobSigUnlock(sigset_t *); static void JobSigReset(void); -#if !defined(MALLOC_OPTIONS) -# define MALLOC_OPTIONS "A" -#endif -const char *malloc_options= MALLOC_OPTIONS; - static unsigned nfds_per_job(void) { @@ -723,15 +713,14 @@ JobPrintCommand(void *cmdp, void *jobp) char *escCmd = NULL; /* Command with quotes/backticks escaped */ char *cmd = (char *)cmdp; Job *job = (Job *)jobp; - int i, j; noSpecials = NoExecute(job->node); if (strcmp(cmd, "...") == 0) { job->node->type |= OP_SAVE_CMDS; if ((job->flags & JOB_IGNDOTS) == 0) { - job->tailCmds = Lst_Succ(Lst_Member(job->node->commands, - cmd)); + LstNode dotsNode = Lst_FindDatum(job->node->commands, cmd); + job->tailCmds = dotsNode != NULL ? LstNode_Next(dotsNode) : NULL; return 1; } return 0; @@ -745,7 +734,7 @@ JobPrintCommand(void *cmdp, void *jobp) numCommands += 1; - cmdStart = cmd = Var_Subst(NULL, cmd, job->node, VARF_WANTRES); + cmdStart = cmd = Var_Subst(cmd, job->node, VARE_WANTRES); cmdTemplate = "%s\n"; @@ -785,15 +774,17 @@ JobPrintCommand(void *cmdp, void *jobp) */ if (!commandShell->hasErrCtl) { + int i, j; + /* Worst that could happen is every char needs escaping. */ escCmd = bmake_malloc((strlen(cmd) * 2) + 1); - for (i = 0, j= 0; cmd[i] != '\0'; i++, j++) { - if (cmd[i] == '$' || cmd[i] == '`' || cmd[i] == '\\' || - cmd[i] == '"') - escCmd[j++] = '\\'; - escCmd[j] = cmd[i]; + for (i = 0, j = 0; cmd[i] != '\0'; i++, j++) { + if (cmd[i] == '$' || cmd[i] == '`' || cmd[i] == '\\' || + cmd[i] == '"') + escCmd[j++] = '\\'; + escCmd[j] = cmd[i]; } - escCmd[j] = 0; + escCmd[j] = '\0'; } if (shutUp) { @@ -926,15 +917,15 @@ JobPrintCommand(void *cmdp, void *jobp) * Always returns 0 * * Side Effects: - * The command is tacked onto the end of postCommands's commands list. + * The command is tacked onto the end of postCommands' commands list. * *----------------------------------------------------------------------- */ static int JobSaveCommand(void *cmd, void *gn) { - cmd = Var_Subst(NULL, (char *)cmd, (GNode *)gn, VARF_WANTRES); - (void)Lst_AtEnd(postCommands->commands, cmd); + cmd = Var_Subst((char *)cmd, (GNode *)gn, VARE_WANTRES); + Lst_Append(postCommands->commands, cmd); return 0; } @@ -1124,7 +1115,7 @@ JobFinish (Job *job, WAIT_T status) if (job->tailCmds != NULL) { Lst_ForEachFrom(job->node->commands, job->tailCmds, JobSaveCommand, - job->node); + job->node); } job->node->made = MADE; if (!(job->flags & JOB_SPECIAL)) @@ -1275,7 +1266,7 @@ Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...)) */ Make_HandleUse(DEFAULT, gn); Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn); - free(p1); + bmake_free(p1); } else if (Dir_MTime(gn, 0) == 0 && (gn->type & OP_SPECIAL) == 0) { /* * The node wasn't the target of an operator we have no .DEFAULT @@ -1302,7 +1293,7 @@ Job_CheckCommands(GNode *gn, void (*abortProc)(const char *, ...)) (void)fprintf(stdout, "%s%s %s (continuing)\n", progname, msg, gn->name); (void)fflush(stdout); - return FALSE; + return FALSE; } else { (*abortProc)("%s%s %s. Stop", progname, msg, gn->name); return FALSE; @@ -1345,7 +1336,7 @@ JobExec(Job *job, char **argv) for (i = 0; argv[i] != NULL; i++) { (void)fprintf(debug_file, "%s ", argv[i]); } - (void)fprintf(debug_file, "\n"); + (void)fprintf(debug_file, "\n"); } /* @@ -1719,7 +1710,7 @@ JobStart(GNode *gn, int flags) * up the graph. */ job->cmdFILE = stdout; - Job_Touch(gn, job->flags&JOB_SILENT); + Job_Touch(gn, job->flags&JOB_SILENT); noExec = TRUE; } /* Just in case it isn't already... */ @@ -1748,8 +1739,8 @@ JobStart(GNode *gn, int flags) if (cmdsOK && aborting == 0) { if (job->tailCmds != NULL) { Lst_ForEachFrom(job->node->commands, job->tailCmds, - JobSaveCommand, - job->node); + JobSaveCommand, + job->node); } job->node->made = MADE; Make_Update(job->node); @@ -1990,8 +1981,8 @@ JobRun(GNode *targ) * and .INTERRUPT job in the parallel job module. This has * the nice side effect that it avoids a lot of other problems. */ - Lst lst = Lst_Init(FALSE); - Lst_AtEnd(lst, targ); + Lst lst = Lst_Init(); + Lst_Append(lst, targ); (void)Make_Run(lst); Lst_Destroy(lst, NULL); JobStart(targ, JOB_SPECIAL); @@ -2218,8 +2209,9 @@ Shell_Init(void) shellName++; } else #endif - shellPath = str_concat(_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH); + shellPath = str_concat3(_PATH_DEFSHELLDIR, "/", shellName); } + Var_Set_with_flags(".SHELL", shellPath, VAR_CMD, VAR_SET_READONLY); if (commandShell->exit == NULL) { commandShell->exit = ""; } @@ -2253,38 +2245,23 @@ Shell_Init(void) const char * Shell_GetNewline(void) { - return commandShell->newline; } void Job_SetPrefix(void) { - if (targPrefix) { free(targPrefix); } else if (!Var_Exists(MAKE_JOB_PREFIX, VAR_GLOBAL)) { Var_Set(MAKE_JOB_PREFIX, "---", VAR_GLOBAL); } - targPrefix = Var_Subst(NULL, "${" MAKE_JOB_PREFIX "}", - VAR_GLOBAL, VARF_WANTRES); + targPrefix = Var_Subst("${" MAKE_JOB_PREFIX "}", + VAR_GLOBAL, VARE_WANTRES); } -/*- - *----------------------------------------------------------------------- - * Job_Init -- - * Initialize the process module - * - * Input: - * - * Results: - * none - * - * Side Effects: - * lists and counters are initialized - *----------------------------------------------------------------------- - */ +/* Initialize the process module. */ void Job_Init(void) { @@ -2390,19 +2367,7 @@ static void JobSigReset(void) (void)bmake_signal(SIGCHLD, SIG_DFL); } -/*- - *----------------------------------------------------------------------- - * JobMatchShell -- - * Find a shell in 'shells' given its name. - * - * Results: - * A pointer to the Shell structure. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ +/* Find a shell in 'shells' given its name, or return NULL. */ static Shell * JobMatchShell(const char *name) { @@ -2425,7 +2390,7 @@ JobMatchShell(const char *name) * line The shell spec * * Results: - * FAILURE if the specification was incorrect. + * FALSE if the specification was incorrect. * * Side Effects: * commandShell points to a Shell structure (either predefined or @@ -2462,12 +2427,13 @@ JobMatchShell(const char *name) * *----------------------------------------------------------------------- */ -ReturnStatus +Boolean Job_ParseShell(char *line) { + Words wordsList; char **words; char **argv; - int argc; + size_t argc; char *path; Shell newShell; Boolean fullSpec = FALSE; @@ -2477,17 +2443,20 @@ Job_ParseShell(char *line) line++; } - free(UNCONST(shellArgv)); + free(shellArgv); memset(&newShell, 0, sizeof(newShell)); /* * Parse the specification by keyword */ - words = brk_string(line, &argc, TRUE, &path); + wordsList = Str_Words(line, TRUE); + words = wordsList.words; + argc = wordsList.len; + path = wordsList.freeIt; if (words == NULL) { Error("Unterminated quoted string [%s]", line); - return FAILURE; + return FALSE; } shellArgv = path; @@ -2526,7 +2495,7 @@ Job_ParseShell(char *line) Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", *argv); free(words); - return FAILURE; + return FALSE; } fullSpec = TRUE; } @@ -2542,13 +2511,13 @@ Job_ParseShell(char *line) if (newShell.name == NULL) { Parse_Error(PARSE_FATAL, "Neither path nor name specified"); free(words); - return FAILURE; + return FALSE; } else { if ((sh = JobMatchShell(newShell.name)) == NULL) { Parse_Error(PARSE_WARNING, "%s: No matching shell", newShell.name); free(words); - return FAILURE; + return FALSE; } commandShell = sh; shellName = newShell.name; @@ -2584,7 +2553,7 @@ Job_ParseShell(char *line) Parse_Error(PARSE_WARNING, "%s: No matching shell", shellName); free(words); - return FAILURE; + return FALSE; } commandShell = sh; } else { @@ -2613,7 +2582,7 @@ Job_ParseShell(char *line) * shell specification. */ free(words); - return SUCCESS; + return TRUE; } /*- @@ -2790,7 +2759,6 @@ Job_AbortAll(void) continue; } - /*- *----------------------------------------------------------------------- * JobRestartJobs -- @@ -3125,7 +3093,7 @@ emul_poll(struct pollfd *fd, int nfd, int timeout) usecs = timeout * 1000; tv.tv_sec = usecs / 1000000; tv.tv_usec = usecs % 1000000; - tvp = &tv; + tvp = &tv; } nselect = select(maxfd + 1, &rfds, &wfds, 0, tvp); @@ -1,4 +1,4 @@ -/* $NetBSD: job.h,v 1.43 2020/07/03 08:13:23 rillig Exp $ */ +/* $NetBSD: job.h,v 1.47 2020/08/29 12:20:17 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -77,8 +77,8 @@ * job.h -- * Definitions pertaining to the running of jobs in parallel mode. */ -#ifndef _JOB_H_ -#define _JOB_H_ +#ifndef MAKE_JOB_H +#define MAKE_JOB_H #define TMPPAT "makeXXXXXX" /* relative to tmpdir */ @@ -110,7 +110,6 @@ emul_poll(struct pollfd *fd, int nfd, int timeout); */ #define POLL_MSEC 5000 - /*- * Job Table definitions. * @@ -164,7 +163,7 @@ typedef struct Job { * commands */ #define JOB_TRACED 0x400 /* we've sent 'set -x' */ - int jobPipe[2]; /* Pipe for readind output from job */ + int jobPipe[2]; /* Pipe for reading output from job */ struct pollfd *inPollfd; /* pollfd associated with inPipe */ char outBuf[JOB_BUFSIZE + 1]; /* Buffer for storing the output of the @@ -179,7 +178,6 @@ typedef struct Job { #define inPipe jobPipe[0] #define outPipe jobPipe[1] - /*- * Shell Specifications: * Each shell type has associated with it the following information: @@ -252,23 +250,20 @@ void Shell_Init(void); const char *Shell_GetNewline(void); void Job_Touch(GNode *, Boolean); Boolean Job_CheckCommands(GNode *, void (*abortProc )(const char *, ...)); -#define CATCH_BLOCK 1 void Job_CatchChildren(void); void Job_CatchOutput(void); void Job_Make(GNode *); void Job_Init(void); -Boolean Job_Full(void); Boolean Job_Empty(void); -ReturnStatus Job_ParseShell(char *); +Boolean Job_ParseShell(char *); int Job_Finish(void); void Job_End(void); void Job_Wait(void); void Job_AbortAll(void); -void JobFlagForMigration(int); void Job_TokenReturn(void); Boolean Job_TokenWithdraw(void); void Job_ServerStart(int, int, int); void Job_SetPrefix(void); Boolean Job_RunTarget(const char *, const char *); -#endif /* _JOB_H_ */ +#endif /* MAKE_JOB_H */ diff --git a/lst.c b/lst.c new file mode 100644 index 000000000000..26b2457cc013 --- /dev/null +++ b/lst.c @@ -0,0 +1,641 @@ +/* $NetBSD: lst.c,v 1.60 2020/08/31 05:56:02 rillig Exp $ */ + +/* + * Copyright (c) 1988, 1989, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Adam de Boor. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#elif defined(HAVE_STDINT_H) +#include <stdint.h> +#endif + +#include "make.h" + +#ifndef MAKE_NATIVE +static char rcsid[] = "$NetBSD: lst.c,v 1.60 2020/08/31 05:56:02 rillig Exp $"; +#else +#include <sys/cdefs.h> +#ifndef lint +__RCSID("$NetBSD: lst.c,v 1.60 2020/08/31 05:56:02 rillig Exp $"); +#endif /* not lint */ +#endif + +struct ListNode { + struct ListNode *prev; /* previous element in list */ + struct ListNode *next; /* next in list */ + uint8_t useCount; /* Count of functions using the node. + * node may not be deleted until count + * goes to 0 */ + Boolean deleted; /* List node should be removed when done */ + union { + void *datum; /* datum associated with this element */ + const GNode *gnode; /* alias, just for debugging */ + const char *str; /* alias, just for debugging */ + }; +}; + +typedef enum { + Head, Middle, Tail, Unknown +} Where; + +struct List { + LstNode first; /* first node in list */ + LstNode last; /* last node in list */ + + /* fields for sequential access */ + Boolean isOpen; /* true if list has been Lst_Open'ed */ + Where lastAccess; /* Where in the list the last access was */ + LstNode curr; /* current node, if open. NULL if + * *just* opened */ + LstNode prev; /* Previous node, if open. Used by Lst_Remove */ +}; + +/* Allocate and initialize a list node. + * + * The fields 'prev' and 'next' must be initialized by the caller. + */ +static LstNode +LstNodeNew(void *datum) +{ + LstNode node = bmake_malloc(sizeof *node); + node->useCount = 0; + node->deleted = FALSE; + node->datum = datum; + return node; +} + +static Boolean +LstIsEmpty(Lst list) +{ + return list->first == NULL; +} + +/* Create and initialize a new, empty list. */ +Lst +Lst_Init(void) +{ + Lst list = bmake_malloc(sizeof *list); + + list->first = NULL; + list->last = NULL; + list->isOpen = FALSE; + list->lastAccess = Unknown; + + return list; +} + +/* Duplicate an entire list, usually by copying the datum pointers. + * If copyProc is given, that function is used to create the new datum from the + * old datum, usually by creating a copy of it. */ +Lst +Lst_Copy(Lst list, LstCopyProc copyProc) +{ + Lst newList; + LstNode node; + + assert(list != NULL); + + newList = Lst_Init(); + + for (node = list->first; node != NULL; node = node->next) { + void *datum = copyProc != NULL ? copyProc(node->datum) : node->datum; + Lst_Append(newList, datum); + } + + return newList; +} + +/* Free a list and all its nodes. The list data itself are not freed though. */ +void +Lst_Free(Lst list) +{ + LstNode node; + LstNode next; + + assert(list != NULL); + + for (node = list->first; node != NULL; node = next) { + next = node->next; + free(node); + } + + free(list); +} + +/* Destroy a list and free all its resources. The freeProc is called with the + * datum from each node in turn before the node is freed. */ +void +Lst_Destroy(Lst list, LstFreeProc freeProc) +{ + LstNode node; + LstNode next; + + assert(list != NULL); + assert(freeProc != NULL); + + for (node = list->first; node != NULL; node = next) { + next = node->next; + freeProc(node->datum); + free(node); + } + + free(list); +} + +/* + * Functions to modify a list + */ + +/* Insert a new node with the given piece of data before the given node in the + * given list. */ +void +Lst_InsertBefore(Lst list, LstNode node, void *datum) +{ + LstNode newNode; + + assert(list != NULL); + assert(!LstIsEmpty(list)); + assert(node != NULL); + assert(datum != NULL); + + newNode = LstNodeNew(datum); + newNode->prev = node->prev; + newNode->next = node; + + if (node->prev != NULL) { + node->prev->next = newNode; + } + node->prev = newNode; + + if (node == list->first) { + list->first = newNode; + } +} + +/* Add a piece of data at the start of the given list. */ +void +Lst_Prepend(Lst list, void *datum) +{ + LstNode node; + + assert(list != NULL); + assert(datum != NULL); + + node = LstNodeNew(datum); + node->prev = NULL; + node->next = list->first; + + if (list->first == NULL) { + list->first = node; + list->last = node; + } else { + list->first->prev = node; + list->first = node; + } +} + +/* Add a piece of data at the end of the given list. */ +void +Lst_Append(Lst list, void *datum) +{ + LstNode node; + + assert(list != NULL); + assert(datum != NULL); + + node = LstNodeNew(datum); + node->prev = list->last; + node->next = NULL; + + if (list->last == NULL) { + list->first = node; + list->last = node; + } else { + list->last->next = node; + list->last = node; + } +} + +/* Remove the given node from the given list. + * The datum stored in the node must be freed by the caller, if necessary. */ +void +Lst_Remove(Lst list, LstNode node) +{ + assert(list != NULL); + assert(node != NULL); + + /* + * unlink it from the list + */ + if (node->next != NULL) { + node->next->prev = node->prev; + } + if (node->prev != NULL) { + node->prev->next = node->next; + } + + /* + * if either the first or last of the list point to this node, + * adjust them accordingly + */ + if (list->first == node) { + list->first = node->next; + } + if (list->last == node) { + list->last = node->prev; + } + + /* + * Sequential access stuff. If the node we're removing is the current + * node in the list, reset the current node to the previous one. If the + * previous one was non-existent (prev == NULL), we set the + * end to be Unknown, since it is. + */ + if (list->isOpen && list->curr == node) { + list->curr = list->prev; + if (list->curr == NULL) { + list->lastAccess = Unknown; + } + } + + /* + * note that the datum is unmolested. The caller must free it as + * necessary and as expected. + */ + if (node->useCount == 0) { + free(node); + } else { + node->deleted = TRUE; + } +} + +/* Replace the datum in the given node with the new datum. */ +void +LstNode_Set(LstNode node, void *datum) +{ + assert(node != NULL); + assert(datum != NULL); + + node->datum = datum; +} + +/* Replace the datum in the given node to NULL. */ +void +LstNode_SetNull(LstNode node) +{ + assert(node != NULL); + + node->datum = NULL; +} + + +/* + * Node-specific functions + */ + +/* Return the first node from the given list, or NULL if the list is empty. */ +LstNode +Lst_First(Lst list) +{ + assert(list != NULL); + + return list->first; +} + +/* Return the last node from the given list, or NULL if the list is empty. */ +LstNode +Lst_Last(Lst list) +{ + assert(list != NULL); + + return list->last; +} + +/* Return the successor to the given node on its list, or NULL. */ +LstNode +LstNode_Next(LstNode node) +{ + assert(node != NULL); + + return node->next; +} + +/* Return the predecessor to the given node on its list, or NULL. */ +LstNode +LstNode_Prev(LstNode node) +{ + assert(node != NULL); + return node->prev; +} + +/* Return the datum stored in the given node. */ +void * +LstNode_Datum(LstNode node) +{ + assert(node != NULL); + return node->datum; +} + + +/* + * Functions for entire lists + */ + +/* Return TRUE if the given list is empty. */ +Boolean +Lst_IsEmpty(Lst list) +{ + assert(list != NULL); + + return LstIsEmpty(list); +} + +/* Return the first node from the list for which the match function returns + * TRUE, or NULL if none of the nodes matched. */ +LstNode +Lst_Find(Lst list, LstFindProc match, const void *matchArgs) +{ + return Lst_FindFrom(list, Lst_First(list), match, matchArgs); +} + +/* Return the first node from the list, starting at the given node, for which + * the match function returns TRUE, or NULL if none of the nodes matches. + * + * The start node may be NULL, in which case nothing is found. This allows + * for passing Lst_First or LstNode_Next as the start node. */ +LstNode +Lst_FindFrom(Lst list, LstNode node, LstFindProc match, const void *matchArgs) +{ + LstNode tln; + + assert(list != NULL); + assert(match != NULL); + + for (tln = node; tln != NULL; tln = tln->next) { + if (match(tln->datum, matchArgs)) + return tln; + } + + return NULL; +} + +/* Return the first node that contains the given datum, or NULL. */ +LstNode +Lst_FindDatum(Lst list, const void *datum) +{ + LstNode node; + + assert(list != NULL); + assert(datum != NULL); + + for (node = list->first; node != NULL; node = node->next) { + if (node->datum == datum) { + return node; + } + } + + return NULL; +} + +/* Apply the given function to each element of the given list. The function + * should return 0 if traversal should continue and non-zero if it should + * abort. */ +int +Lst_ForEach(Lst list, LstActionProc proc, void *procData) +{ + if (LstIsEmpty(list)) + return 0; /* XXX: Document what this value means. */ + return Lst_ForEachFrom(list, Lst_First(list), proc, procData); +} + +/* Apply the given function to each element of the given list, starting from + * the given node. The function should return 0 if traversal should continue, + * and non-zero if it should abort. */ +int +Lst_ForEachFrom(Lst list, LstNode node, + LstActionProc proc, void *procData) +{ + LstNode tln = node; + LstNode next; + Boolean done; + int result; + + assert(list != NULL); + assert(node != NULL); + assert(proc != NULL); + + do { + /* + * Take care of having the current element deleted out from under + * us. + */ + + next = tln->next; + + /* + * We're done with the traversal if + * - the next node to examine doesn't exist and + * - nothing's been added after the current node (check this + * after proc() has been called). + */ + done = next == NULL; + + tln->useCount++; + result = (*proc)(tln->datum, procData); + tln->useCount--; + + /* + * Now check whether a node has been added. + * Note: this doesn't work if this node was deleted before + * the new node was added. + */ + if (next != tln->next) { + next = tln->next; + done = 0; + } + + if (tln->deleted) { + free((char *)tln); + } + tln = next; + } while (!result && !LstIsEmpty(list) && !done); + + return result; +} + +/* Move all nodes from list2 to the end of list1. + * List2 is destroyed and freed. */ +void +Lst_MoveAll(Lst list1, Lst list2) +{ + assert(list1 != NULL); + assert(list2 != NULL); + + if (list2->first != NULL) { + list2->first->prev = list1->last; + if (list1->last != NULL) { + list1->last->next = list2->first; + } else { + list1->first = list2->first; + } + list1->last = list2->last; + } + free(list2); +} + +/* Copy the element data from src to the start of dst. */ +void +Lst_PrependAll(Lst dst, Lst src) +{ + LstNode node; + for (node = src->last; node != NULL; node = node->prev) + Lst_Prepend(dst, node->datum); +} + +/* Copy the element data from src to the end of dst. */ +void +Lst_AppendAll(Lst dst, Lst src) +{ + LstNode node; + for (node = src->first; node != NULL; node = node->next) + Lst_Append(dst, node->datum); +} + +/* + * these functions are for dealing with a list as a table, of sorts. + * An idea of the "current element" is kept and used by all the functions + * between Lst_Open() and Lst_Close(). + * + * The sequential functions access the list in a slightly different way. + * CurPtr points to their idea of the current node in the list and they + * access the list based on it. + */ + +/* Open a list for sequential access. A list can still be searched, etc., + * without confusing these functions. */ +void +Lst_Open(Lst list) +{ + assert(list != NULL); + assert(!list->isOpen); + + list->isOpen = TRUE; + list->lastAccess = LstIsEmpty(list) ? Head : Unknown; + list->curr = NULL; +} + +/* Return the next node for the given list, or NULL if the end has been + * reached. */ +LstNode +Lst_Next(Lst list) +{ + LstNode node; + + assert(list != NULL); + assert(list->isOpen); + + list->prev = list->curr; + + if (list->curr == NULL) { + if (list->lastAccess == Unknown) { + /* + * If we're just starting out, lastAccess will be Unknown. + * Then we want to start this thing off in the right + * direction -- at the start with lastAccess being Middle. + */ + list->curr = node = list->first; + list->lastAccess = Middle; + } else { + node = NULL; + list->lastAccess = Tail; + } + } else { + node = list->curr->next; + list->curr = node; + + if (node == list->first || node == NULL) { + /* + * If back at the front, then we've hit the end... + */ + list->lastAccess = Tail; + } else { + /* + * Reset to Middle if gone past first. + */ + list->lastAccess = Middle; + } + } + + return node; +} + +/* Close a list which was opened for sequential access. */ +void +Lst_Close(Lst list) +{ + assert(list != NULL); + assert(list->isOpen); + + list->isOpen = FALSE; + list->lastAccess = Unknown; +} + + +/* + * for using the list as a queue + */ + +/* Add the datum to the tail of the given list. */ +void +Lst_Enqueue(Lst list, void *datum) +{ + Lst_Append(list, datum); +} + +/* Remove and return the datum at the head of the given list. */ +void * +Lst_Dequeue(Lst list) +{ + void *datum; + + assert(list != NULL); + assert(!LstIsEmpty(list)); + + datum = list->first->datum; + Lst_Remove(list, list->first); + assert(datum != NULL); + return datum; +} @@ -1,4 +1,4 @@ -/* $NetBSD: lst.h,v 1.20 2014/09/07 20:55:34 joerg Exp $ */ +/* $NetBSD: lst.h,v 1.60 2020/09/02 23:33:13 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -73,117 +73,107 @@ * from: @(#)lst.h 8.1 (Berkeley) 6/6/93 */ -/*- - * lst.h -- - * Header for using the list library - */ -#ifndef _LST_H_ -#define _LST_H_ - -#include <sys/param.h> -#include <stdlib.h> +/* Doubly-linked lists of arbitrary pointers. */ -#include "sprite.h" +#ifndef MAKE_LST_H +#define MAKE_LST_H -/* - * basic typedef. This is what the Lst_ functions handle - */ +#include <sys/param.h> +#include <stdlib.h> +/* A doubly-linked list of pointers. */ typedef struct List *Lst; +/* A single node in the doubly-linked list. */ typedef struct ListNode *LstNode; -typedef void *DuplicateProc(void *); -typedef void FreeProc(void *); +/* Copy a node, usually by allocating a copy of the given object. + * For reference-counted objects, the original object may need to be + * modified, therefore the parameter is not const. */ +typedef void *LstCopyProc(void *); +/* Free the datum of a node, called before freeing the node itself. */ +typedef void LstFreeProc(void *); +/* Return TRUE if the datum matches the args, for Lst_Find. */ +typedef Boolean LstFindProc(const void *datum, const void *args); +/* An action for Lst_ForEach. */ +typedef int LstActionProc(void *datum, void *args); -#define LST_CONCNEW 0 /* create new LstNode's when using Lst_Concat */ -#define LST_CONCLINK 1 /* relink LstNode's when using Lst_Concat */ +/* Create or destroy a list */ -/* - * Creation/destruction functions - */ -/* Create a new list */ -Lst Lst_Init(Boolean); -/* Duplicate an existing list */ -Lst Lst_Duplicate(Lst, DuplicateProc *); -/* Destroy an old one */ -void Lst_Destroy(Lst, FreeProc *); -/* True if list is empty */ -Boolean Lst_IsEmpty(Lst); +/* Create a new list. */ +Lst Lst_Init(void); +/* Duplicate an existing list. */ +Lst Lst_Copy(Lst, LstCopyProc); +/* Free the list, leaving the node data unmodified. */ +void Lst_Free(Lst); +/* Free the list, freeing the node data using the given function. */ +void Lst_Destroy(Lst, LstFreeProc); -/* - * Functions to modify a list - */ -/* Insert an element before another */ -ReturnStatus Lst_InsertBefore(Lst, LstNode, void *); -/* Insert an element after another */ -ReturnStatus Lst_InsertAfter(Lst, LstNode, void *); -/* Place an element at the front of a lst. */ -ReturnStatus Lst_AtFront(Lst, void *); -/* Place an element at the end of a lst. */ -ReturnStatus Lst_AtEnd(Lst, void *); -/* Remove an element */ -ReturnStatus Lst_Remove(Lst, LstNode); -/* Replace a node with a new value */ -ReturnStatus Lst_Replace(LstNode, void *); -/* Concatenate two lists */ -ReturnStatus Lst_Concat(Lst, Lst, int); +/* Get information about a list */ -/* - * Node-specific functions - */ -/* Return first element in list */ -LstNode Lst_First(Lst); -/* Return last element in list */ -LstNode Lst_Last(Lst); -/* Return successor to given element */ -LstNode Lst_Succ(LstNode); -/* Return predecessor to given element */ -LstNode Lst_Prev(LstNode); -/* Get datum from LstNode */ -void *Lst_Datum(LstNode); +Boolean Lst_IsEmpty(Lst); +/* Return the first node of the list, or NULL. */ +LstNode Lst_First(Lst); +/* Return the last node of the list, or NULL. */ +LstNode Lst_Last(Lst); +/* Find the first node for which the function returns TRUE, or NULL. */ +LstNode Lst_Find(Lst, LstFindProc, const void *); +/* Find the first node for which the function returns TRUE, or NULL. + * The search starts at the given node, towards the end of the list. */ +LstNode Lst_FindFrom(Lst, LstNode, LstFindProc, const void *); +/* Find the first node that contains the given datum, or NULL. */ +LstNode Lst_FindDatum(Lst, const void *); -/* - * Functions for entire lists - */ -/* Find an element in a list */ -LstNode Lst_Find(Lst, const void *, int (*)(const void *, const void *)); -/* Find an element starting from somewhere */ -LstNode Lst_FindFrom(Lst, LstNode, const void *, - int (*cProc)(const void *, const void *)); -/* - * See if the given datum is on the list. Returns the LstNode containing - * the datum - */ -LstNode Lst_Member(Lst, void *); -/* Apply a function to all elements of a lst */ -int Lst_ForEach(Lst, int (*)(void *, void *), void *); -/* - * Apply a function to all elements of a lst starting from a certain point. - * If the list is circular, the application will wrap around to the - * beginning of the list again. - */ -int Lst_ForEachFrom(Lst, LstNode, int (*)(void *, void *), - void *); -/* - * these functions are for dealing with a list as a table, of sorts. - * An idea of the "current element" is kept and used by all the functions - * between Lst_Open() and Lst_Close(). - */ -/* Open the list */ -ReturnStatus Lst_Open(Lst); -/* Next element please */ -LstNode Lst_Next(Lst); -/* Done yet? */ -Boolean Lst_IsAtEnd(Lst); -/* Finish table access */ -void Lst_Close(Lst); +/* Modify a list */ -/* - * for using the list as a queue - */ -/* Place an element at tail of queue */ -ReturnStatus Lst_EnQueue(Lst, void *); -/* Remove an element from head of queue */ -void *Lst_DeQueue(Lst); +/* Insert a datum before the given node. */ +void Lst_InsertBefore(Lst, LstNode, void *); +/* Place a datum at the front of the list. */ +void Lst_Prepend(Lst, void *); +/* Place a datum at the end of the list. */ +void Lst_Append(Lst, void *); +/* Remove the node from the list. */ +void Lst_Remove(Lst, LstNode); +void Lst_PrependAll(Lst, Lst); +void Lst_AppendAll(Lst, Lst); +void Lst_MoveAll(Lst, Lst); + +/* Node-specific functions */ + +/* Return the successor of the node, or NULL. */ +LstNode LstNode_Next(LstNode); +/* Return the predecessor of the node, or NULL. */ +LstNode LstNode_Prev(LstNode); +/* Return the datum of the node. Usually not NULL. */ +void *LstNode_Datum(LstNode); +/* Replace the value of the node. */ +void LstNode_Set(LstNode, void *); +/* Set the value of the node to NULL. Having NULL in a list is unusual. */ +void LstNode_SetNull(LstNode); + +/* Iterating over a list, using a callback function */ + +/* Apply a function to each datum of the list, until the callback function + * returns non-zero. */ +int Lst_ForEach(Lst, LstActionProc, void *); +/* Apply a function to each datum of the list, starting at the node, + * until the callback function returns non-zero. */ +int Lst_ForEachFrom(Lst, LstNode, LstActionProc, void *); + +/* Iterating over a list while keeping track of the current node and possible + * concurrent modifications */ + +/* Start iterating the list. */ +void Lst_Open(Lst); +/* Return the next node, or NULL. */ +LstNode Lst_Next(Lst); +/* Finish iterating the list. */ +void Lst_Close(Lst); + +/* Using the list as a queue */ + +/* Add a datum at the tail of the queue. */ +void Lst_Enqueue(Lst, void *); +/* Remove the head node of the queue and return its datum. */ +void *Lst_Dequeue(Lst); -#endif /* _LST_H_ */ +#endif /* MAKE_LST_H */ diff --git a/lst.lib/Makefile b/lst.lib/Makefile deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/lst.lib/Makefile +++ /dev/null diff --git a/lst.lib/lstAppend.c b/lst.lib/lstAppend.c deleted file mode 100644 index 97e60d959d7d..000000000000 --- a/lst.lib/lstAppend.c +++ /dev/null @@ -1,121 +0,0 @@ -/* $NetBSD: lstAppend.c,v 1.15 2020/07/03 08:37:56 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstAppend.c,v 1.15 2020/07/03 08:37:56 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstAppend.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstAppend.c,v 1.15 2020/07/03 08:37:56 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstAppend.c -- - * Add a new node with a new datum after an existing node - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_InsertAfter -- - * Create a new node and add it to the given list after the given node. - * - * Input: - * l affected list - * ln node after which to append the datum - * d said datum - * - * Results: - * SUCCESS if all went well. - * - * Side Effects: - * A new ListNode is created and linked in to the List. The lastPtr - * field of the List will be altered if ln is the last node in the - * list. lastPtr and firstPtr will alter if the list was empty and - * ln was NULL. - * - *----------------------------------------------------------------------- - */ -ReturnStatus -Lst_InsertAfter(Lst l, LstNode ln, void *d) -{ - List list; - ListNode lNode; - ListNode nLNode; - - if (LstValid (l) && (ln == NULL && LstIsEmpty (l))) { - goto ok; - } - - if (!LstValid (l) || LstIsEmpty (l) || ! LstNodeValid (ln, l)) { - return FAILURE; - } - ok: - - list = l; - lNode = ln; - - PAlloc (nLNode, ListNode); - nLNode->datum = d; - nLNode->useCount = nLNode->flags = 0; - - if (lNode == NULL) { - if (list->isCirc) { - nLNode->nextPtr = nLNode->prevPtr = nLNode; - } else { - nLNode->nextPtr = nLNode->prevPtr = NULL; - } - list->firstPtr = list->lastPtr = nLNode; - } else { - nLNode->prevPtr = lNode; - nLNode->nextPtr = lNode->nextPtr; - - lNode->nextPtr = nLNode; - if (nLNode->nextPtr != NULL) { - nLNode->nextPtr->prevPtr = nLNode; - } - - if (lNode == list->lastPtr) { - list->lastPtr = nLNode; - } - } - - return SUCCESS; -} diff --git a/lst.lib/lstAtEnd.c b/lst.lib/lstAtEnd.c deleted file mode 100644 index 4eadfdb0e7f3..000000000000 --- a/lst.lib/lstAtEnd.c +++ /dev/null @@ -1,79 +0,0 @@ -/* $NetBSD: lstAtEnd.c,v 1.14 2020/07/03 08:37:56 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstAtEnd.c,v 1.14 2020/07/03 08:37:56 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstAtEnd.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstAtEnd.c,v 1.14 2020/07/03 08:37:56 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstAtEnd.c -- - * Add a node at the end of the list - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_AtEnd -- - * Add a node to the end of the given list - * - * Input: - * l List to which to add the datum - * d Datum to add - * - * Results: - * SUCCESS if life is good. - * - * Side Effects: - * A new ListNode is created and added to the list. - * - *----------------------------------------------------------------------- - */ -ReturnStatus -Lst_AtEnd(Lst l, void *d) -{ - LstNode end; - - end = Lst_Last(l); - return Lst_InsertAfter(l, end, d); -} diff --git a/lst.lib/lstAtFront.c b/lst.lib/lstAtFront.c deleted file mode 100644 index 724713c092ed..000000000000 --- a/lst.lib/lstAtFront.c +++ /dev/null @@ -1,76 +0,0 @@ -/* $NetBSD: lstAtFront.c,v 1.14 2020/07/03 08:37:56 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstAtFront.c,v 1.14 2020/07/03 08:37:56 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstAtFront.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstAtFront.c,v 1.14 2020/07/03 08:37:56 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstAtFront.c -- - * Add a node at the front of the list - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_AtFront -- - * Place a piece of data at the front of a list - * - * Results: - * SUCCESS or FAILURE - * - * Side Effects: - * A new ListNode is created and stuck at the front of the list. - * hence, firstPtr (and possible lastPtr) in the list are altered. - * - *----------------------------------------------------------------------- - */ -ReturnStatus -Lst_AtFront(Lst l, void *d) -{ - LstNode front; - - front = Lst_First(l); - return Lst_InsertBefore(l, front, d); -} diff --git a/lst.lib/lstClose.c b/lst.lib/lstClose.c deleted file mode 100644 index a1a3e9da80de..000000000000 --- a/lst.lib/lstClose.c +++ /dev/null @@ -1,85 +0,0 @@ -/* $NetBSD: lstClose.c,v 1.12 2020/07/03 08:37:56 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstClose.c,v 1.12 2020/07/03 08:37:56 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstClose.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstClose.c,v 1.12 2020/07/03 08:37:56 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstClose.c -- - * Close a list for sequential access. - * The sequential functions access the list in a slightly different way. - * CurPtr points to their idea of the current node in the list and they - * access the list based on it. Because the list is circular, Lst_Next - * and Lst_Prev will go around the list forever. Lst_IsAtEnd must be - * used to determine when to stop. - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Close -- - * Close a list which was opened for sequential access. - * - * Input: - * l The list to close - * - * Results: - * None. - * - * Side Effects: - * The list is closed. - * - *----------------------------------------------------------------------- - */ -void -Lst_Close(Lst l) -{ - List list = l; - - if (LstValid(l) == TRUE) { - list->isOpen = FALSE; - list->atEnd = Unknown; - } -} diff --git a/lst.lib/lstConcat.c b/lst.lib/lstConcat.c deleted file mode 100644 index 2f667c5b0119..000000000000 --- a/lst.lib/lstConcat.c +++ /dev/null @@ -1,184 +0,0 @@ -/* $NetBSD: lstConcat.c,v 1.17 2020/07/03 08:37:56 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstConcat.c,v 1.17 2020/07/03 08:37:56 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstConcat.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstConcat.c,v 1.17 2020/07/03 08:37:56 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * listConcat.c -- - * Function to concatentate two lists. - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Concat -- - * Concatenate two lists. New elements are created to hold the data - * elements, if specified, but the elements themselves are not copied. - * If the elements should be duplicated to avoid confusion with another - * list, the Lst_Duplicate function should be called first. - * If LST_CONCLINK is specified, the second list is destroyed since - * its pointers have been corrupted and the list is no longer useable. - * - * Input: - * l1 The list to which l2 is to be appended - * l2 The list to append to l1 - * flags LST_CONCNEW if LstNode's should be duplicated - * LST_CONCLINK if should just be relinked - * - * Results: - * SUCCESS if all went well. FAILURE otherwise. - * - * Side Effects: - * New elements are created and appended the first list. - *----------------------------------------------------------------------- - */ -ReturnStatus -Lst_Concat(Lst l1, Lst l2, int flags) -{ - ListNode ln; /* original LstNode */ - ListNode nln; /* new LstNode */ - ListNode last; /* the last element in the list. Keeps - * bookkeeping until the end */ - List list1 = l1; - List list2 = l2; - - if (!LstValid (l1) || !LstValid (l2)) { - return FAILURE; - } - - if (flags == LST_CONCLINK) { - if (list2->firstPtr != NULL) { - /* - * We set the nextPtr of the - * last element of list two to be NIL to make the loop easier and - * so we don't need an extra case should the first list turn - * out to be non-circular -- the final element will already point - * to NIL space and the first element will be untouched if it - * existed before and will also point to NIL space if it didn't. - */ - list2->lastPtr->nextPtr = NULL; - /* - * So long as the second list isn't empty, we just link the - * first element of the second list to the last element of the - * first list. If the first list isn't empty, we then link the - * last element of the list to the first element of the second list - * The last element of the second list, if it exists, then becomes - * the last element of the first list. - */ - list2->firstPtr->prevPtr = list1->lastPtr; - if (list1->lastPtr != NULL) { - list1->lastPtr->nextPtr = list2->firstPtr; - } else { - list1->firstPtr = list2->firstPtr; - } - list1->lastPtr = list2->lastPtr; - } - if (list1->isCirc && list1->firstPtr != NULL) { - /* - * If the first list is supposed to be circular and it is (now) - * non-empty, we must make sure it's circular by linking the - * first element to the last and vice versa - */ - list1->firstPtr->prevPtr = list1->lastPtr; - list1->lastPtr->nextPtr = list1->firstPtr; - } - free(l2); - } else if (list2->firstPtr != NULL) { - /* - * We set the nextPtr of the last element of list 2 to be nil to make - * the loop less difficult. The loop simply goes through the entire - * second list creating new LstNodes and filling in the nextPtr, and - * prevPtr to fit into l1 and its datum field from the - * datum field of the corresponding element in l2. The 'last' node - * follows the last of the new nodes along until the entire l2 has - * been appended. Only then does the bookkeeping catch up with the - * changes. During the first iteration of the loop, if 'last' is nil, - * the first list must have been empty so the newly-created node is - * made the first node of the list. - */ - list2->lastPtr->nextPtr = NULL; - for (last = list1->lastPtr, ln = list2->firstPtr; - ln != NULL; - ln = ln->nextPtr) - { - PAlloc (nln, ListNode); - nln->datum = ln->datum; - if (last != NULL) { - last->nextPtr = nln; - } else { - list1->firstPtr = nln; - } - nln->prevPtr = last; - nln->flags = nln->useCount = 0; - last = nln; - } - - /* - * Finish bookkeeping. The last new element becomes the last element - * of list one. - */ - list1->lastPtr = last; - - /* - * The circularity of both list one and list two must be corrected - * for -- list one because of the new nodes added to it; list two - * because of the alteration of list2->lastPtr's nextPtr to ease the - * above for loop. - */ - if (list1->isCirc) { - list1->lastPtr->nextPtr = list1->firstPtr; - list1->firstPtr->prevPtr = list1->lastPtr; - } else { - last->nextPtr = NULL; - } - - if (list2->isCirc) { - list2->lastPtr->nextPtr = list2->firstPtr; - } - } - - return SUCCESS; -} diff --git a/lst.lib/lstDatum.c b/lst.lib/lstDatum.c deleted file mode 100644 index c8ccb558f3dc..000000000000 --- a/lst.lib/lstDatum.c +++ /dev/null @@ -1,76 +0,0 @@ -/* $NetBSD: lstDatum.c,v 1.14 2020/07/03 08:37:56 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstDatum.c,v 1.14 2020/07/03 08:37:56 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstDatum.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstDatum.c,v 1.14 2020/07/03 08:37:56 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstDatum.c -- - * Return the datum associated with a list node. - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Datum -- - * Return the datum stored in the given node. - * - * Results: - * The datum or NULL if the node is invalid. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -void * -Lst_Datum(LstNode ln) -{ - if (ln != NULL) { - return ln->datum; - } else { - return NULL; - } -} diff --git a/lst.lib/lstDeQueue.c b/lst.lib/lstDeQueue.c deleted file mode 100644 index 0f1452e4ac7e..000000000000 --- a/lst.lib/lstDeQueue.c +++ /dev/null @@ -1,86 +0,0 @@ -/* $NetBSD: lstDeQueue.c,v 1.15 2020/07/03 08:37:56 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstDeQueue.c,v 1.15 2020/07/03 08:37:56 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstDeQueue.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstDeQueue.c,v 1.15 2020/07/03 08:37:56 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstDeQueue.c -- - * Remove the node and return its datum from the head of the list - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_DeQueue -- - * Remove and return the datum at the head of the given list. - * - * Results: - * The datum in the node at the head or NULL if the list - * is empty. - * - * Side Effects: - * The head node is removed from the list. - * - *----------------------------------------------------------------------- - */ -void * -Lst_DeQueue(Lst l) -{ - void *rd; - ListNode tln; - - tln = Lst_First(l); - if (tln == NULL) { - return NULL; - } - - rd = tln->datum; - if (Lst_Remove(l, tln) == FAILURE) { - return NULL; - } else { - return rd; - } -} diff --git a/lst.lib/lstDestroy.c b/lst.lib/lstDestroy.c deleted file mode 100644 index 92c5b2b2050c..000000000000 --- a/lst.lib/lstDestroy.c +++ /dev/null @@ -1,101 +0,0 @@ -/* $NetBSD: lstDestroy.c,v 1.16 2008/12/13 15:19:29 dsl Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstDestroy.c,v 1.16 2008/12/13 15:19:29 dsl Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstDestroy.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstDestroy.c,v 1.16 2008/12/13 15:19:29 dsl Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstDestroy.c -- - * Nuke a list and all its resources - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Destroy -- - * Destroy a list and free all its resources. If the freeProc is - * given, it is called with the datum from each node in turn before - * the node is freed. - * - * Results: - * None. - * - * Side Effects: - * The given list is freed in its entirety. - * - *----------------------------------------------------------------------- - */ -void -Lst_Destroy(Lst list, FreeProc *freeProc) -{ - ListNode ln; - ListNode tln = NULL; - - if (list == NULL) - return; - - /* To ease scanning */ - if (list->lastPtr != NULL) - list->lastPtr->nextPtr = NULL; - else { - free(list); - return; - } - - if (freeProc) { - for (ln = list->firstPtr; ln != NULL; ln = tln) { - tln = ln->nextPtr; - freeProc(ln->datum); - free(ln); - } - } else { - for (ln = list->firstPtr; ln != NULL; ln = tln) { - tln = ln->nextPtr; - free(ln); - } - } - - free(list); -} diff --git a/lst.lib/lstDupl.c b/lst.lib/lstDupl.c deleted file mode 100644 index 6318ee4e462a..000000000000 --- a/lst.lib/lstDupl.c +++ /dev/null @@ -1,107 +0,0 @@ -/* $NetBSD: lstDupl.c,v 1.17 2020/07/03 08:37:56 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstDupl.c,v 1.17 2020/07/03 08:37:56 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstDupl.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstDupl.c,v 1.17 2020/07/03 08:37:56 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * listDupl.c -- - * Duplicate a list. This includes duplicating the individual - * elements. - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Duplicate -- - * Duplicate an entire list. If a function to copy a void *is - * given, the individual client elements will be duplicated as well. - * - * Input: - * l the list to duplicate - * copyProc A function to duplicate each void * - * - * Results: - * The new Lst structure or NULL if failure. - * - * Side Effects: - * A new list is created. - *----------------------------------------------------------------------- - */ -Lst -Lst_Duplicate(Lst l, DuplicateProc *copyProc) -{ - Lst nl; - ListNode ln; - List list = l; - - if (!LstValid (l)) { - return NULL; - } - - nl = Lst_Init(list->isCirc); - if (nl == NULL) { - return NULL; - } - - ln = list->firstPtr; - while (ln != NULL) { - if (copyProc != NULL) { - if (Lst_AtEnd(nl, copyProc(ln->datum)) == FAILURE) { - return NULL; - } - } else if (Lst_AtEnd(nl, ln->datum) == FAILURE) { - return NULL; - } - - if (list->isCirc && ln == list->lastPtr) { - ln = NULL; - } else { - ln = ln->nextPtr; - } - } - - return nl; -} diff --git a/lst.lib/lstEnQueue.c b/lst.lib/lstEnQueue.c deleted file mode 100644 index c6941a8eb9d3..000000000000 --- a/lst.lib/lstEnQueue.c +++ /dev/null @@ -1,77 +0,0 @@ -/* $NetBSD: lstEnQueue.c,v 1.14 2020/07/03 08:37:56 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstEnQueue.c,v 1.14 2020/07/03 08:37:56 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstEnQueue.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstEnQueue.c,v 1.14 2020/07/03 08:37:56 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstEnQueue.c-- - * Treat the list as a queue and place a datum at its end - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_EnQueue -- - * Add the datum to the tail of the given list. - * - * Results: - * SUCCESS or FAILURE as returned by Lst_InsertAfter. - * - * Side Effects: - * the lastPtr field is altered all the time and the firstPtr field - * will be altered if the list used to be empty. - * - *----------------------------------------------------------------------- - */ -ReturnStatus -Lst_EnQueue(Lst l, void *d) -{ - if (LstValid (l) == FALSE) { - return FAILURE; - } - - return Lst_InsertAfter(l, Lst_Last(l), d); -} diff --git a/lst.lib/lstFind.c b/lst.lib/lstFind.c deleted file mode 100644 index a1d27d3ad686..000000000000 --- a/lst.lib/lstFind.c +++ /dev/null @@ -1,73 +0,0 @@ -/* $NetBSD: lstFind.c,v 1.16 2020/07/03 08:37:56 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstFind.c,v 1.16 2020/07/03 08:37:56 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstFind.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstFind.c,v 1.16 2020/07/03 08:37:56 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstFind.c -- - * Find a node on a list. - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Find -- - * Find a node on the given list using the given comparison function - * and the given datum. - * - * Results: - * The found node or NULL if none matches. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -LstNode -Lst_Find(Lst l, const void *d, int (*cProc)(const void *, const void *)) -{ - return Lst_FindFrom(l, Lst_First(l), d, cProc); -} diff --git a/lst.lib/lstFindFrom.c b/lst.lib/lstFindFrom.c deleted file mode 100644 index 676c07392039..000000000000 --- a/lst.lib/lstFindFrom.c +++ /dev/null @@ -1,89 +0,0 @@ -/* $NetBSD: lstFindFrom.c,v 1.16 2020/07/03 08:37:56 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstFindFrom.c,v 1.16 2020/07/03 08:37:56 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstFindFrom.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstFindFrom.c,v 1.16 2020/07/03 08:37:56 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstFindFrom.c -- - * Find a node on a list from a given starting point. Used by Lst_Find. - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_FindFrom -- - * Search for a node starting and ending with the given one on the - * given list using the passed datum and comparison function to - * determine when it has been found. - * - * Results: - * The found node or NULL - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -LstNode -Lst_FindFrom(Lst l, LstNode ln, const void *d, - int (*cProc)(const void *, const void *)) -{ - ListNode tln; - - if (!LstValid (l) || LstIsEmpty (l) || !LstNodeValid (ln, l)) { - return NULL; - } - - tln = ln; - - do { - if ((*cProc)(tln->datum, d) == 0) - return tln; - tln = tln->nextPtr; - } while (tln != ln && tln != NULL); - - return NULL; -} diff --git a/lst.lib/lstFirst.c b/lst.lib/lstFirst.c deleted file mode 100644 index a79db57120dd..000000000000 --- a/lst.lib/lstFirst.c +++ /dev/null @@ -1,76 +0,0 @@ -/* $NetBSD: lstFirst.c,v 1.13 2020/07/03 08:37:56 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstFirst.c,v 1.13 2020/07/03 08:37:56 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstFirst.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstFirst.c,v 1.13 2020/07/03 08:37:56 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstFirst.c -- - * Return the first node of a list - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_First -- - * Return the first node on the given list. - * - * Results: - * The first node or NULL if the list is empty. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -LstNode -Lst_First(Lst l) -{ - if (!LstValid (l) || LstIsEmpty (l)) { - return NULL; - } else { - return l->firstPtr; - } -} diff --git a/lst.lib/lstForEach.c b/lst.lib/lstForEach.c deleted file mode 100644 index dc2fdd8bfc57..000000000000 --- a/lst.lib/lstForEach.c +++ /dev/null @@ -1,75 +0,0 @@ -/* $NetBSD: lstForEach.c,v 1.14 2020/07/03 08:37:57 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstForEach.c,v 1.14 2020/07/03 08:37:57 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstForEach.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstForEach.c,v 1.14 2020/07/03 08:37:57 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstForeach.c -- - * Perform a given function on all elements of a list. - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_ForEach -- - * Apply the given function to each element of the given list. The - * function should return 0 if Lst_ForEach should continue and non- - * zero if it should abort. - * - * Results: - * None. - * - * Side Effects: - * Only those created by the passed-in function. - * - *----------------------------------------------------------------------- - */ -/*VARARGS2*/ -int -Lst_ForEach(Lst l, int (*proc)(void *, void *), void *d) -{ - return Lst_ForEachFrom(l, Lst_First(l), proc, d); -} diff --git a/lst.lib/lstForEachFrom.c b/lst.lib/lstForEachFrom.c deleted file mode 100644 index a08ddf35935b..000000000000 --- a/lst.lib/lstForEachFrom.c +++ /dev/null @@ -1,124 +0,0 @@ -/* $NetBSD: lstForEachFrom.c,v 1.18 2020/07/03 08:37:57 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstForEachFrom.c,v 1.18 2020/07/03 08:37:57 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstForEachFrom.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstForEachFrom.c,v 1.18 2020/07/03 08:37:57 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * lstForEachFrom.c -- - * Perform a given function on all elements of a list starting from - * a given point. - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_ForEachFrom -- - * Apply the given function to each element of the given list. The - * function should return 0 if traversal should continue and non- - * zero if it should abort. - * - * Results: - * None. - * - * Side Effects: - * Only those created by the passed-in function. - * - *----------------------------------------------------------------------- - */ -/*VARARGS2*/ -int -Lst_ForEachFrom(Lst l, LstNode ln, int (*proc)(void *, void *), - void *d) -{ - ListNode tln = ln; - List list = l; - ListNode next; - Boolean done; - int result; - - if (!LstValid (list) || LstIsEmpty (list)) { - return 0; - } - - do { - /* - * Take care of having the current element deleted out from under - * us. - */ - - next = tln->nextPtr; - - /* - * We're done with the traversal if - * - the next node to examine is the first in the queue or - * doesn't exist and - * - nothing's been added after the current node (check this - * after proc() has been called). - */ - done = (next == NULL || next == list->firstPtr); - - (void) tln->useCount++; - result = (*proc) (tln->datum, d); - (void) tln->useCount--; - - /* - * Now check whether a node has been added. - * Note: this doesn't work if this node was deleted before - * the new node was added. - */ - if (next != tln->nextPtr) { - next = tln->nextPtr; - done = 0; - } - - if (tln->flags & LN_DELETED) { - free((char *)tln); - } - tln = next; - } while (!result && !LstIsEmpty(list) && !done); - - return result; -} diff --git a/lst.lib/lstInit.c b/lst.lib/lstInit.c deleted file mode 100644 index 3255da7e59a1..000000000000 --- a/lst.lib/lstInit.c +++ /dev/null @@ -1,85 +0,0 @@ -/* $NetBSD: lstInit.c,v 1.13 2020/07/03 08:37:57 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstInit.c,v 1.13 2020/07/03 08:37:57 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstInit.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstInit.c,v 1.13 2020/07/03 08:37:57 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * init.c -- - * Initialize a new linked list. - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Init -- - * Create and initialize a new list. - * - * Input: - * circ TRUE if the list should be made circular - * - * Results: - * The created list. - * - * Side Effects: - * A list is created, what else? - * - *----------------------------------------------------------------------- - */ -Lst -Lst_Init(Boolean circ) -{ - List nList; - - PAlloc (nList, List); - - nList->firstPtr = NULL; - nList->lastPtr = NULL; - nList->isOpen = FALSE; - nList->isCirc = circ; - nList->atEnd = Unknown; - - return nList; -} diff --git a/lst.lib/lstInsert.c b/lst.lib/lstInsert.c deleted file mode 100644 index 845b8899e03b..000000000000 --- a/lst.lib/lstInsert.c +++ /dev/null @@ -1,121 +0,0 @@ -/* $NetBSD: lstInsert.c,v 1.15 2020/07/03 08:37:57 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstInsert.c,v 1.15 2020/07/03 08:37:57 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstInsert.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstInsert.c,v 1.15 2020/07/03 08:37:57 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstInsert.c -- - * Insert a new datum before an old one - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_InsertBefore -- - * Insert a new node with the given piece of data before the given - * node in the given list. - * - * Input: - * l list to manipulate - * ln node before which to insert d - * d datum to be inserted - * - * Results: - * SUCCESS or FAILURE. - * - * Side Effects: - * the firstPtr field will be changed if ln is the first node in the - * list. - * - *----------------------------------------------------------------------- - */ -ReturnStatus -Lst_InsertBefore(Lst l, LstNode ln, void *d) -{ - ListNode nLNode; /* new lnode for d */ - ListNode lNode = ln; - List list = l; - - - /* - * check validity of arguments - */ - if (LstValid (l) && (LstIsEmpty (l) && ln == NULL)) - goto ok; - - if (!LstValid (l) || LstIsEmpty (l) || !LstNodeValid (ln, l)) { - return FAILURE; - } - - ok: - PAlloc (nLNode, ListNode); - - nLNode->datum = d; - nLNode->useCount = nLNode->flags = 0; - - if (ln == NULL) { - if (list->isCirc) { - nLNode->prevPtr = nLNode->nextPtr = nLNode; - } else { - nLNode->prevPtr = nLNode->nextPtr = NULL; - } - list->firstPtr = list->lastPtr = nLNode; - } else { - nLNode->prevPtr = lNode->prevPtr; - nLNode->nextPtr = lNode; - - if (nLNode->prevPtr != NULL) { - nLNode->prevPtr->nextPtr = nLNode; - } - lNode->prevPtr = nLNode; - - if (lNode == list->firstPtr) { - list->firstPtr = nLNode; - } - } - - return SUCCESS; -} diff --git a/lst.lib/lstInt.h b/lst.lib/lstInt.h deleted file mode 100644 index ac53dcb67d77..000000000000 --- a/lst.lib/lstInt.h +++ /dev/null @@ -1,105 +0,0 @@ -/* $NetBSD: lstInt.h,v 1.22 2014/09/07 20:55:34 joerg Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from: @(#)lstInt.h 8.1 (Berkeley) 6/6/93 - */ - -/*- - * lstInt.h -- - * Internals for the list library - */ -#ifndef _LSTINT_H_ -#define _LSTINT_H_ - -#include "../lst.h" -#include "../make_malloc.h" - -typedef struct ListNode { - struct ListNode *prevPtr; /* previous element in list */ - struct ListNode *nextPtr; /* next in list */ - unsigned int useCount:8, /* Count of functions using the node. - * node may not be deleted until count - * goes to 0 */ - flags:8; /* Node status flags */ - void *datum; /* datum associated with this element */ -} *ListNode; -/* - * Flags required for synchronization - */ -#define LN_DELETED 0x0001 /* List node should be removed when done */ - -typedef enum { - Head, Middle, Tail, Unknown -} Where; - -typedef struct List { - ListNode firstPtr; /* first node in list */ - ListNode lastPtr; /* last node in list */ - Boolean isCirc; /* true if the list should be considered - * circular */ -/* - * fields for sequential access - */ - Where atEnd; /* Where in the list the last access was */ - Boolean isOpen; /* true if list has been Lst_Open'ed */ - ListNode curPtr; /* current node, if open. NULL if - * *just* opened */ - ListNode prevPtr; /* Previous node, if open. Used by - * Lst_Remove */ -} *List; - -/* - * PAlloc (var, ptype) -- - * Allocate a pointer-typedef structure 'ptype' into the variable 'var' - */ -#define PAlloc(var,ptype) var = (ptype) bmake_malloc(sizeof *(var)) - -/* - * LstValid (l) -- - * Return TRUE if the list l is valid - */ -#define LstValid(l) ((Lst)(l) != NULL) - -/* - * LstNodeValid (ln, l) -- - * Return TRUE if the LstNode ln is valid with respect to l - */ -#define LstNodeValid(ln, l) ((ln) != NULL) - -/* - * LstIsEmpty (l) -- - * TRUE if the list l is empty. - */ -#define LstIsEmpty(l) (((List)(l))->firstPtr == NULL) - -#endif /* _LSTINT_H_ */ diff --git a/lst.lib/lstIsAtEnd.c b/lst.lib/lstIsAtEnd.c deleted file mode 100644 index c5add4d9867f..000000000000 --- a/lst.lib/lstIsAtEnd.c +++ /dev/null @@ -1,86 +0,0 @@ -/* $NetBSD: lstIsAtEnd.c,v 1.14 2020/07/03 08:37:57 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstIsAtEnd.c,v 1.14 2020/07/03 08:37:57 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstIsAtEnd.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstIsAtEnd.c,v 1.14 2020/07/03 08:37:57 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstIsAtEnd.c -- - * Tell if the current node is at the end of the list. - * The sequential functions access the list in a slightly different way. - * CurPtr points to their idea of the current node in the list and they - * access the list based on it. Because the list is circular, Lst_Next - * and Lst_Prev will go around the list forever. Lst_IsAtEnd must be - * used to determine when to stop. - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_IsAtEnd -- - * Return true if have reached the end of the given list. - * - * Results: - * TRUE if at the end of the list (this includes the list not being - * open or being invalid) or FALSE if not. We return TRUE if the list - * is invalid or unopend so as to cause the caller to exit its loop - * asap, the assumption being that the loop is of the form - * while (!Lst_IsAtEnd (l)) { - * ... - * } - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -Boolean -Lst_IsAtEnd(Lst l) -{ - List list = l; - - return !LstValid (l) || !list->isOpen || - list->atEnd == Head || list->atEnd == Tail; -} diff --git a/lst.lib/lstIsEmpty.c b/lst.lib/lstIsEmpty.c deleted file mode 100644 index ccf4525a3506..000000000000 --- a/lst.lib/lstIsEmpty.c +++ /dev/null @@ -1,74 +0,0 @@ -/* $NetBSD: lstIsEmpty.c,v 1.12 2020/07/03 08:37:57 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstIsEmpty.c,v 1.12 2020/07/03 08:37:57 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstIsEmpty.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstIsEmpty.c,v 1.12 2020/07/03 08:37:57 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstIsEmpty.c -- - * A single function to decide if a list is empty - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_IsEmpty -- - * Return TRUE if the given list is empty. - * - * Results: - * TRUE if the list is empty, FALSE otherwise. - * - * Side Effects: - * None. - * - * A list is considered empty if its firstPtr == NULL (or if - * the list itself is NULL). - *----------------------------------------------------------------------- - */ -Boolean -Lst_IsEmpty(Lst l) -{ - return !LstValid(l) || LstIsEmpty(l); -} diff --git a/lst.lib/lstLast.c b/lst.lib/lstLast.c deleted file mode 100644 index 1d65bf19473e..000000000000 --- a/lst.lib/lstLast.c +++ /dev/null @@ -1,76 +0,0 @@ -/* $NetBSD: lstLast.c,v 1.13 2020/07/03 08:37:57 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstLast.c,v 1.13 2020/07/03 08:37:57 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstLast.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstLast.c,v 1.13 2020/07/03 08:37:57 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstLast.c -- - * Return the last element of a list - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Last -- - * Return the last node on the list l. - * - * Results: - * The requested node or NULL if the list is empty. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -LstNode -Lst_Last(Lst l) -{ - if (!LstValid(l) || LstIsEmpty (l)) { - return NULL; - } else { - return l->lastPtr; - } -} diff --git a/lst.lib/lstMember.c b/lst.lib/lstMember.c deleted file mode 100644 index e9046aca1436..000000000000 --- a/lst.lib/lstMember.c +++ /dev/null @@ -1,77 +0,0 @@ -/* $NetBSD: lstMember.c,v 1.14 2013/11/14 00:01:28 sjg Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstMember.c,v 1.14 2013/11/14 00:01:28 sjg Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstMember.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstMember.c,v 1.14 2013/11/14 00:01:28 sjg Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * lstMember.c -- - * See if a given datum is on a given list. - */ - -#include "lstInt.h" - -LstNode -Lst_Member(Lst l, void *d) -{ - List list = l; - ListNode lNode; - - if (list == NULL) { - return NULL; - } - lNode = list->firstPtr; - if (lNode == NULL) { - return NULL; - } - - do { - if (lNode->datum == d) { - return lNode; - } - lNode = lNode->nextPtr; - } while (lNode != NULL && lNode != list->firstPtr); - - return NULL; -} diff --git a/lst.lib/lstNext.c b/lst.lib/lstNext.c deleted file mode 100644 index 9c180d2cfad1..000000000000 --- a/lst.lib/lstNext.c +++ /dev/null @@ -1,119 +0,0 @@ -/* $NetBSD: lstNext.c,v 1.13 2020/07/03 08:37:57 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstNext.c,v 1.13 2020/07/03 08:37:57 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstNext.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstNext.c,v 1.13 2020/07/03 08:37:57 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstNext.c -- - * Return the next node for a list. - * The sequential functions access the list in a slightly different way. - * CurPtr points to their idea of the current node in the list and they - * access the list based on it. Because the list is circular, Lst_Next - * and Lst_Prev will go around the list forever. Lst_IsAtEnd must be - * used to determine when to stop. - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Next -- - * Return the next node for the given list. - * - * Results: - * The next node or NULL if the list has yet to be opened. Also - * if the list is non-circular and the end has been reached, NULL - * is returned. - * - * Side Effects: - * the curPtr field is updated. - * - *----------------------------------------------------------------------- - */ -LstNode -Lst_Next(Lst l) -{ - ListNode tln; - List list = l; - - if ((LstValid (l) == FALSE) || - (list->isOpen == FALSE)) { - return NULL; - } - - list->prevPtr = list->curPtr; - - if (list->curPtr == NULL) { - if (list->atEnd == Unknown) { - /* - * If we're just starting out, atEnd will be Unknown. - * Then we want to start this thing off in the right - * direction -- at the start with atEnd being Middle. - */ - list->curPtr = tln = list->firstPtr; - list->atEnd = Middle; - } else { - tln = NULL; - list->atEnd = Tail; - } - } else { - tln = list->curPtr->nextPtr; - list->curPtr = tln; - - if (tln == list->firstPtr || tln == NULL) { - /* - * If back at the front, then we've hit the end... - */ - list->atEnd = Tail; - } else { - /* - * Reset to Middle if gone past first. - */ - list->atEnd = Middle; - } - } - - return tln; -} diff --git a/lst.lib/lstOpen.c b/lst.lib/lstOpen.c deleted file mode 100644 index 919dd6d5000c..000000000000 --- a/lst.lib/lstOpen.c +++ /dev/null @@ -1,86 +0,0 @@ -/* $NetBSD: lstOpen.c,v 1.13 2020/07/03 08:37:57 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstOpen.c,v 1.13 2020/07/03 08:37:57 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstOpen.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstOpen.c,v 1.13 2020/07/03 08:37:57 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstOpen.c -- - * Open a list for sequential access. The sequential functions access the - * list in a slightly different way. CurPtr points to their idea of the - * current node in the list and they access the list based on it. - * If the list is circular, Lst_Next and Lst_Prev will go around - * the list forever. Lst_IsAtEnd must be used to determine when to stop. - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Open -- - * Open a list for sequential access. A list can still be searched, - * etc., without confusing these functions. - * - * Results: - * SUCCESS or FAILURE. - * - * Side Effects: - * isOpen is set TRUE and curPtr is set to NULL so the - * other sequential functions no it was just opened and can choose - * the first element accessed based on this. - * - *----------------------------------------------------------------------- - */ -ReturnStatus -Lst_Open(Lst l) -{ - if (LstValid (l) == FALSE) { - return FAILURE; - } - (l)->isOpen = TRUE; - (l)->atEnd = LstIsEmpty (l) ? Head : Unknown; - (l)->curPtr = NULL; - - return SUCCESS; -} diff --git a/lst.lib/lstPrev.c b/lst.lib/lstPrev.c deleted file mode 100644 index b6c548d9a523..000000000000 --- a/lst.lib/lstPrev.c +++ /dev/null @@ -1,78 +0,0 @@ -/* $NetBSD: lstPrev.c,v 1.4 2020/07/03 08:37:57 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstPrev.c,v 1.4 2020/07/03 08:37:57 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstSucc.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstPrev.c,v 1.4 2020/07/03 08:37:57 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstPrev.c -- - * return the predecessor to a given node - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Prev -- - * Return the predecessor to the given node on its list. - * - * Results: - * The predecessor of the node, if it exists (note that on a circular - * list, if the node is the only one in the list, it is its own - * predecessor). - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -LstNode -Lst_Prev(LstNode ln) -{ - if (ln == NULL) { - return NULL; - } else { - return ln->prevPtr; - } -} diff --git a/lst.lib/lstRemove.c b/lst.lib/lstRemove.c deleted file mode 100644 index 59245499bdc4..000000000000 --- a/lst.lib/lstRemove.c +++ /dev/null @@ -1,134 +0,0 @@ -/* $NetBSD: lstRemove.c,v 1.17 2020/07/03 08:37:57 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstRemove.c,v 1.17 2020/07/03 08:37:57 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstRemove.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstRemove.c,v 1.17 2020/07/03 08:37:57 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstRemove.c -- - * Remove an element from a list - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Remove -- - * Remove the given node from the given list. - * - * Results: - * SUCCESS or FAILURE. - * - * Side Effects: - * The list's firstPtr will be set to NULL if ln is the last - * node on the list. firsPtr and lastPtr will be altered if ln is - * either the first or last node, respectively, on the list. - * - *----------------------------------------------------------------------- - */ -ReturnStatus -Lst_Remove(Lst l, LstNode ln) -{ - List list = l; - ListNode lNode = ln; - - if (!LstValid (l) || !LstNodeValid (ln, l)) { - return FAILURE; - } - - /* - * unlink it from the list - */ - if (lNode->nextPtr != NULL) { - lNode->nextPtr->prevPtr = lNode->prevPtr; - } - if (lNode->prevPtr != NULL) { - lNode->prevPtr->nextPtr = lNode->nextPtr; - } - - /* - * if either the firstPtr or lastPtr of the list point to this node, - * adjust them accordingly - */ - if (list->firstPtr == lNode) { - list->firstPtr = lNode->nextPtr; - } - if (list->lastPtr == lNode) { - list->lastPtr = lNode->prevPtr; - } - - /* - * Sequential access stuff. If the node we're removing is the current - * node in the list, reset the current node to the previous one. If the - * previous one was non-existent (prevPtr == NULL), we set the - * end to be Unknown, since it is. - */ - if (list->isOpen && (list->curPtr == lNode)) { - list->curPtr = list->prevPtr; - if (list->curPtr == NULL) { - list->atEnd = Unknown; - } - } - - /* - * the only way firstPtr can still point to ln is if ln is the last - * node on the list (the list is circular, so lNode->nextptr == lNode in - * this case). The list is, therefore, empty and is marked as such - */ - if (list->firstPtr == lNode) { - list->firstPtr = NULL; - } - - /* - * note that the datum is unmolested. The caller must free it as - * necessary and as expected. - */ - if (lNode->useCount == 0) { - free(ln); - } else { - lNode->flags |= LN_DELETED; - } - - return SUCCESS; -} diff --git a/lst.lib/lstReplace.c b/lst.lib/lstReplace.c deleted file mode 100644 index f30cb00855e3..000000000000 --- a/lst.lib/lstReplace.c +++ /dev/null @@ -1,77 +0,0 @@ -/* $NetBSD: lstReplace.c,v 1.14 2020/07/03 08:37:57 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstReplace.c,v 1.14 2020/07/03 08:37:57 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstReplace.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstReplace.c,v 1.14 2020/07/03 08:37:57 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstReplace.c -- - * Replace the datum in a node with a new datum - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Replace -- - * Replace the datum in the given node with the new datum - * - * Results: - * SUCCESS or FAILURE. - * - * Side Effects: - * The datum field fo the node is altered. - * - *----------------------------------------------------------------------- - */ -ReturnStatus -Lst_Replace(LstNode ln, void *d) -{ - if (ln == NULL) { - return FAILURE; - } else { - (ln)->datum = d; - return SUCCESS; - } -} diff --git a/lst.lib/lstSucc.c b/lst.lib/lstSucc.c deleted file mode 100644 index b3f73bb15fd2..000000000000 --- a/lst.lib/lstSucc.c +++ /dev/null @@ -1,78 +0,0 @@ -/* $NetBSD: lstSucc.c,v 1.14 2020/07/03 08:37:57 rillig Exp $ */ - -/* - * Copyright (c) 1988, 1989, 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Adam de Boor. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: lstSucc.c,v 1.14 2020/07/03 08:37:57 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -#if 0 -static char sccsid[] = "@(#)lstSucc.c 8.1 (Berkeley) 6/6/93"; -#else -__RCSID("$NetBSD: lstSucc.c,v 1.14 2020/07/03 08:37:57 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - -/*- - * LstSucc.c -- - * return the successor to a given node - */ - -#include "lstInt.h" - -/*- - *----------------------------------------------------------------------- - * Lst_Succ -- - * Return the successor to the given node on its list. - * - * Results: - * The successor of the node, if it exists (note that on a circular - * list, if the node is the only one in the list, it is its own - * successor). - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------- - */ -LstNode -Lst_Succ(LstNode ln) -{ - if (ln == NULL) { - return NULL; - } else { - return ln->nextPtr; - } -} @@ -1,4 +1,4 @@ -/* $NetBSD: main.c,v 1.279 2020/07/03 08:13:23 rillig Exp $ */ +/* $NetBSD: main.c,v 1.331 2020/08/30 19:56:02 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -69,7 +69,7 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: main.c,v 1.279 2020/07/03 08:13:23 rillig Exp $"; +static char rcsid[] = "$NetBSD: main.c,v 1.331 2020/08/30 19:56:02 rillig Exp $"; #else #include <sys/cdefs.h> #ifndef lint @@ -81,7 +81,7 @@ __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993\ #if 0 static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94"; #else -__RCSID("$NetBSD: main.c,v 1.279 2020/07/03 08:13:23 rillig Exp $"); +__RCSID("$NetBSD: main.c,v 1.331 2020/08/30 19:56:02 rillig Exp $"); #endif #endif /* not lint */ #endif @@ -124,13 +124,13 @@ __RCSID("$NetBSD: main.c,v 1.279 2020/07/03 08:13:23 rillig Exp $"); #include <sys/utsname.h> #include "wait.h" +#include <ctype.h> #include <errno.h> #include <signal.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <time.h> -#include <ctype.h> #include "make.h" #include "hash.h" @@ -162,7 +162,8 @@ static Lst makefiles; /* ordered list of makefiles to read */ static int printVars; /* -[vV] argument */ #define COMPAT_VARS 1 #define EXPAND_VARS 2 -static Lst variables; /* list of variables to print */ +static Lst variables; /* list of variables to print + * (for -v and -V) */ int maxJobs; /* -j argument */ static int maxJobTokens; /* -j argument */ Boolean compatMake; /* -B argument */ @@ -180,14 +181,13 @@ Boolean beSilent; /* -s flag */ Boolean oldVars; /* variable substitution style */ Boolean checkEnvFirst; /* -e flag */ Boolean parseWarnFatal; /* -W flag */ -Boolean jobServer; /* -J flag */ static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */ Boolean varNoExportEnv; /* -X flag */ Boolean doing_depend; /* Set while reading .depend */ static Boolean jobsRunning; /* TRUE if the jobs might be running */ static const char * tracefile; static void MainParseArgs(int, char **); -static int ReadMakefile(const void *, const void *); +static int ReadMakefile(const char *); static void usage(void) MAKE_ATTR_DEAD; static void purge_cached_realpaths(void); @@ -257,7 +257,7 @@ parse_debug_options(const char *argvalue) for (modules = argvalue; *modules; ++modules) { switch (*modules) { case 'A': - debug = ~0; + debug = ~(0|DEBUG_LINT); break; case 'a': debug |= DEBUG_ARCH; @@ -291,9 +291,15 @@ parse_debug_options(const char *argvalue) ++modules; } break; + case 'h': + debug |= DEBUG_HASH; + break; case 'j': debug |= DEBUG_JOB; break; + case 'L': + debug |= DEBUG_LINT; + break; case 'l': debug |= DEBUG_LOUD; break; @@ -375,7 +381,7 @@ debug_setbuf: /* * does path contain any relative components */ -static int +static Boolean is_relpath(const char *path) { const char *cp; @@ -383,10 +389,7 @@ is_relpath(const char *path) if (path[0] != '/') return TRUE; cp = path; - do { - cp = strstr(cp, "/."); - if (!cp) - break; + while ((cp = strstr(cp, "/.")) != NULL) { cp += 2; if (cp[0] == '/' || cp[0] == '\0') return TRUE; @@ -394,7 +397,7 @@ is_relpath(const char *path) if (cp[1] == '/' || cp[1] == '\0') return TRUE; } - } while (cp); + } return FALSE; } @@ -416,7 +419,7 @@ static void MainParseArgs(int argc, char **argv) { char *p; - int c = '?'; + char c = '?'; int arginc; char *argvalue; const char *getopt_def; @@ -531,7 +534,6 @@ rearg: } else { Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL); Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); - jobServer = TRUE; } break; case 'N': @@ -553,7 +555,7 @@ rearg: case 'v': if (argvalue == NULL) goto noarg; printVars = c == 'v' ? EXPAND_VARS : COMPAT_VARS; - (void)Lst_AtEnd(variables, argvalue); + Lst_Append(variables, argvalue); Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); break; @@ -581,7 +583,7 @@ rearg: break; case 'f': if (argvalue == NULL) goto noarg; - (void)Lst_AtEnd(makefiles, argvalue); + Lst_Append(makefiles, argvalue); break; case 'i': ignoreErrors = TRUE; @@ -674,7 +676,7 @@ rearg: Punt("illegal (null) argument."); if (*argv[1] == '-' && !dashDash) goto rearg; - (void)Lst_AtEnd(create, bmake_strdup(argv[1])); + Lst_Append(create, bmake_strdup(argv[1])); } return; @@ -705,12 +707,10 @@ noarg: void Main_ParseArgLine(const char *line) { - char **argv; /* Manufactured argument vector */ - int argc; /* Number of arguments in argv */ - char *args; /* Space used by the args */ - char *buf, *p1; - char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1); - size_t len; + Words words; + char *p1; + const char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1); + char *buf; if (line == NULL) return; @@ -733,21 +733,19 @@ Main_ParseArgLine(const char *line) return; } #endif - buf = bmake_malloc(len = strlen(line) + strlen(argv0) + 2); - (void)snprintf(buf, len, "%s %s", argv0, line); + buf = str_concat3(argv0, " ", line); free(p1); - argv = brk_string(buf, &argc, TRUE, &args); - if (argv == NULL) { + words = Str_Words(buf, TRUE); + if (words.words == NULL) { Error("Unterminated quoted string [%s]", buf); free(buf); return; } free(buf); - MainParseArgs(argc, argv); + MainParseArgs((int)words.len, words.words); - free(args); - free(argv); + Words_Free(words); } Boolean @@ -775,7 +773,7 @@ Main_SetObjdir(const char *fmt, ...) (void)fprintf(stderr, "make warning: %s: %s.\n", path, strerror(errno)); } else { - strncpy(objdir, path, MAXPATHLEN); + snprintf(objdir, sizeof objdir, "%s", path); Var_Set(".OBJDIR", objdir, VAR_GLOBAL); setenv("PWD", objdir, 1); Dir_InitDot(); @@ -792,37 +790,44 @@ Main_SetObjdir(const char *fmt, ...) static Boolean Main_SetVarObjdir(const char *var, const char *suffix) { - char *p, *path, *xpath; + char *path_freeIt; + const char *path = Var_Value(var, VAR_CMD, &path_freeIt); + const char *xpath; + char *xpath_freeIt; - if ((path = Var_Value(var, VAR_CMD, &p)) == NULL || - *path == '\0') + if (path == NULL || path[0] == '\0') { + bmake_free(path_freeIt); return FALSE; + } /* expand variable substitutions */ + xpath = path; + xpath_freeIt = NULL; if (strchr(path, '$') != 0) - xpath = Var_Subst(NULL, path, VAR_GLOBAL, VARF_WANTRES); - else - xpath = path; + xpath = xpath_freeIt = Var_Subst(path, VAR_GLOBAL, + VARE_WANTRES); (void)Main_SetObjdir("%s%s", xpath, suffix); - if (xpath != path) - free(xpath); - free(p); + bmake_free(xpath_freeIt); + bmake_free(path_freeIt); return TRUE; } -/*- - * ReadAllMakefiles -- - * wrapper around ReadMakefile() to read all. - * - * Results: - * TRUE if ok, FALSE on error - */ -static int -ReadAllMakefiles(const void *p, const void *q) +/* Read and parse the makefile. + * Return TRUE if reading the makefile succeeded, for Lst_Find. */ +static Boolean +ReadMakefileSucceeded(const void *fname, const void *unused) +{ + return ReadMakefile(fname) == 0; +} + +/* Read and parse the makefile. + * Return TRUE if reading the makefile failed, for Lst_Find. */ +static Boolean +ReadMakefileFailed(const void *fname, const void *unused) { - return ReadMakefile(p, q) == 0; + return ReadMakefile(fname) != 0; } int @@ -835,7 +840,7 @@ str2Lst_Append(Lst lp, char *str, const char *sep) sep = " \t"; for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) { - (void)Lst_AtEnd(lp, cp); + Lst_Append(lp, cp); n++; } return n; @@ -863,13 +868,13 @@ siginfo(int signo MAKE_ATTR_UNUSED) void MakeMode(const char *mode) { - char *mp = NULL; + char *mode_freeIt = NULL; - if (!mode) - mode = mp = Var_Subst(NULL, "${" MAKE_MODE ":tl}", - VAR_GLOBAL, VARF_WANTRES); + if (mode == NULL) + mode = mode_freeIt = Var_Subst("${" MAKE_MODE ":tl}", + VAR_GLOBAL, VARE_WANTRES); - if (mode && *mode) { + if (mode[0] != '\0') { if (strstr(mode, "compat")) { compatMake = TRUE; forceJobs = FALSE; @@ -880,7 +885,7 @@ MakeMode(const char *mode) #endif } - free(mp); + free(mode_freeIt); } static void @@ -896,15 +901,13 @@ doPrintVars(void) else expandVars = getBoolean(".MAKE.EXPAND_VARIABLES", FALSE); - for (ln = Lst_First(variables); ln != NULL; - ln = Lst_Succ(ln)) { - char *var = (char *)Lst_Datum(ln); - char *value; + for (ln = Lst_First(variables); ln != NULL; ln = LstNode_Next(ln)) { + char *var = LstNode_Datum(ln); + const char *value; char *p1; if (strchr(var, '$')) { - value = p1 = Var_Subst(NULL, var, VAR_GLOBAL, - VARF_WANTRES); + value = p1 = Var_Subst(var, VAR_GLOBAL, VARE_WANTRES); } else if (expandVars) { char tmp[128]; int len = snprintf(tmp, sizeof(tmp), "${%s}", var); @@ -912,13 +915,12 @@ doPrintVars(void) if (len >= (int)sizeof(tmp)) Fatal("%s: variable name too big: %s", progname, var); - value = p1 = Var_Subst(NULL, tmp, VAR_GLOBAL, - VARF_WANTRES); + value = p1 = Var_Subst(tmp, VAR_GLOBAL, VARE_WANTRES); } else { value = Var_Value(var, VAR_GLOBAL, &p1); } printf("%s\n", value ? value : ""); - free(p1); + bmake_free(p1); } } @@ -962,7 +964,7 @@ runTargets(void) Compat_Run(targs); outOfDate = FALSE; } - Lst_Destroy(targs, NULL); + Lst_Free(targs); return outOfDate; } @@ -1079,7 +1081,7 @@ main(int argc, char **argv) #else #ifndef MACHINE_ARCH #ifdef MAKE_MACHINE_ARCH - machine_arch = MAKE_MACHINE_ARCH; + machine_arch = MAKE_MACHINE_ARCH; #else machine_arch = "unknown"; #endif @@ -1113,11 +1115,11 @@ main(int argc, char **argv) VAR_GLOBAL); Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL); - create = Lst_Init(FALSE); - makefiles = Lst_Init(FALSE); + create = Lst_Init(); + makefiles = Lst_Init(); printVars = 0; debugVflag = FALSE; - variables = Lst_Init(FALSE); + variables = Lst_Init(); beSilent = FALSE; /* Print commands as executed */ ignoreErrors = FALSE; /* Pay attention to non-zero returns */ noExecute = FALSE; /* Execute all commands */ @@ -1199,7 +1201,7 @@ main(int argc, char **argv) #ifdef USE_META meta_init(); #endif - Dir_Init(NULL); /* Dir_* safe to call from MainParseArgs */ + Dir_Init(); /* * First snag any flags out of the MAKE environment variable. @@ -1265,8 +1267,8 @@ main(int argc, char **argv) (void)strncpy(curdir, pwd, MAXPATHLEN); } } - free(ptmp1); - free(ptmp2); + bmake_free(ptmp1); + bmake_free(ptmp2); } #endif Var_Set(".CURDIR", curdir, VAR_GLOBAL); @@ -1280,7 +1282,7 @@ main(int argc, char **argv) * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none * of these paths exist, just use .CURDIR. */ - Dir_Init(curdir); + Dir_InitDir(curdir); (void)Main_SetObjdir("%s", curdir); if (!Main_SetVarObjdir("MAKEOBJDIRPREFIX", curdir) && @@ -1312,10 +1314,8 @@ main(int argc, char **argv) if (!Lst_IsEmpty(create)) { LstNode ln; - for (ln = Lst_First(create); ln != NULL; - ln = Lst_Succ(ln)) { - char *name = (char *)Lst_Datum(ln); - + for (ln = Lst_First(create); ln != NULL; ln = LstNode_Next(ln)) { + char *name = LstNode_Datum(ln); Var_Append(".TARGETS", name, VAR_GLOBAL); } } else @@ -1327,7 +1327,8 @@ main(int argc, char **argv) * add the directories from the DEFSYSPATH (more than one may be given * as dir1:...:dirn) to the system include path. */ - if (syspath == NULL || *syspath == '\0') + /* XXX: mismatch: the -m option sets sysIncPath, not syspath */ + if (syspath == NULL || syspath[0] == '\0') syspath = defsyspath; else syspath = bmake_strdup(syspath); @@ -1353,48 +1354,46 @@ main(int argc, char **argv) /* * Read in the built-in rules first, followed by the specified - * makefile, if it was (makefile != NULL), or the default - * makefile and Makefile, in that order, if it wasn't. + * makefiles, or the default makefile and Makefile, in that order, + * if no makefiles were given on the command line. */ if (!noBuiltins) { LstNode ln; - sysMkPath = Lst_Init(FALSE); + sysMkPath = Lst_Init(); Dir_Expand(_PATH_DEFSYSMK, Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath, sysMkPath); if (Lst_IsEmpty(sysMkPath)) Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK); - ln = Lst_Find(sysMkPath, NULL, ReadMakefile); + ln = Lst_Find(sysMkPath, ReadMakefileSucceeded, NULL); if (ln == NULL) Fatal("%s: cannot open %s.", progname, - (char *)Lst_Datum(ln)); + (char *)LstNode_Datum(Lst_First(sysMkPath))); } if (!Lst_IsEmpty(makefiles)) { LstNode ln; - ln = Lst_Find(makefiles, NULL, ReadAllMakefiles); + ln = Lst_Find(makefiles, ReadMakefileFailed, NULL); if (ln != NULL) Fatal("%s: cannot open %s.", progname, - (char *)Lst_Datum(ln)); + (char *)LstNode_Datum(ln)); } else { - p1 = Var_Subst(NULL, "${" MAKEFILE_PREFERENCE "}", - VAR_CMD, VARF_WANTRES); - if (p1) { + p1 = Var_Subst("${" MAKEFILE_PREFERENCE "}", + VAR_CMD, VARE_WANTRES); (void)str2Lst_Append(makefiles, p1, NULL); - (void)Lst_Find(makefiles, NULL, ReadMakefile); + (void)Lst_Find(makefiles, ReadMakefileSucceeded, NULL); free(p1); - } } /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ if (!noBuiltins || !printVars) { - makeDependfile = Var_Subst(NULL, "${.MAKE.DEPENDFILE:T}", - VAR_CMD, VARF_WANTRES); + makeDependfile = Var_Subst("${.MAKE.DEPENDFILE:T}", + VAR_CMD, VARE_WANTRES); doing_depend = TRUE; - (void)ReadMakefile(makeDependfile, NULL); + (void)ReadMakefile(makeDependfile); doing_depend = FALSE; } @@ -1404,14 +1403,14 @@ main(int argc, char **argv) MakeMode(NULL); Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL); - free(p1); + bmake_free(p1); if (!forceJobs && !compatMake && Var_Exists(".MAKE.JOBS", VAR_GLOBAL)) { char *value; int n; - value = Var_Subst(NULL, "${.MAKE.JOBS}", VAR_GLOBAL, VARF_WANTRES); + value = Var_Subst("${.MAKE.JOBS}", VAR_GLOBAL, VARE_WANTRES); n = strtol(value, NULL, 0); if (n < 1) { (void)fprintf(stderr, "%s: illegal value for .MAKE.JOBS -- must be positive integer!\n", @@ -1439,8 +1438,9 @@ main(int argc, char **argv) if (!compatMake) Job_ServerStart(maxJobTokens, jp_0, jp_1); if (DEBUG(JOB)) - fprintf(debug_file, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", - jp_0, jp_1, maxJobs, maxJobTokens, compatMake); + fprintf(debug_file, + "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", + jp_0, jp_1, maxJobs, maxJobTokens, compatMake ? 1 : 0); if (!printVars) Main_ExportMAKEFLAGS(TRUE); /* initial export */ @@ -1461,7 +1461,7 @@ main(int argc, char **argv) */ static char VPATH[] = "${VPATH}"; - vpath = Var_Subst(NULL, VPATH, VAR_CMD, VARF_WANTRES); + vpath = Var_Subst(VPATH, VAR_CMD, VARE_WANTRES); path = vpath; do { /* skip to end of directory */ @@ -1502,9 +1502,9 @@ main(int argc, char **argv) } #ifdef CLEANUP - Lst_Destroy(variables, NULL); - Lst_Destroy(makefiles, NULL); - Lst_Destroy(create, (FreeProc *)free); + Lst_Free(variables); + Lst_Free(makefiles); + Lst_Destroy(create, free); #endif /* print the graph now it's been processed if the user requested it */ @@ -1522,7 +1522,7 @@ main(int argc, char **argv) meta_finish(); #endif Suff_End(); - Targ_End(); + Targ_End(); Arch_End(); Var_End(); Parse_End(); @@ -1533,23 +1533,16 @@ main(int argc, char **argv) return outOfDate ? 1 : 0; } -/*- - * ReadMakefile -- - * Open and parse the given makefile. +/* Open and parse the given makefile, with all its side effects. * * Results: * 0 if ok. -1 if couldn't open file. - * - * Side Effects: - * lots */ static int -ReadMakefile(const void *p, const void *q MAKE_ATTR_UNUSED) +ReadMakefile(const char *fname) { - const char *fname = p; /* makefile to read */ int fd; - size_t len = MAXPATHLEN; - char *name, *path = bmake_malloc(len); + char *name, *path = NULL; if (!strcmp(fname, "-")) { Parse_File(NULL /*stdin*/, -1); @@ -1557,22 +1550,16 @@ ReadMakefile(const void *p, const void *q MAKE_ATTR_UNUSED) } else { /* if we've chdir'd, rebuild the path name */ if (strcmp(curdir, objdir) && *fname != '/') { - size_t plen = strlen(curdir) + strlen(fname) + 2; - if (len < plen) - path = bmake_realloc(path, len = 2 * plen); - - (void)snprintf(path, len, "%s/%s", curdir, fname); + path = str_concat3(curdir, "/", fname); fd = open(path, O_RDONLY); if (fd != -1) { fname = path; goto found; } + free(path); /* If curdir failed, try objdir (ala .depend) */ - plen = strlen(objdir) + strlen(fname) + 2; - if (len < plen) - path = bmake_realloc(path, len = 2 * plen); - (void)snprintf(path, len, "%s/%s", objdir, fname); + path = str_concat3(objdir, "/", fname); fd = open(path, O_RDONLY); if (fd != -1) { fname = path; @@ -1613,31 +1600,32 @@ found: /*- * Cmd_Exec -- * Execute the command in cmd, and return the output of that command - * in a string. + * in a string. In the output, newlines are replaced with spaces. * * Results: - * A string containing the output of the command, or the empty string - * If errnum is not NULL, it contains the reason for the command failure + * A string containing the output of the command, or the empty string. + * *errfmt returns a format string describing the command failure, + * if any, using a single %s conversion specification. * * Side Effects: * The string must be freed by the caller. */ char * -Cmd_Exec(const char *cmd, const char **errnum) +Cmd_Exec(const char *cmd, const char **errfmt) { const char *args[4]; /* Args for invoking the shell */ int fds[2]; /* Pipe streams */ int cpid; /* Child PID */ int pid; /* PID from wait() */ - char *res; /* result */ WAIT_T status; /* command exit status */ Buffer buf; /* buffer to store the result */ + ssize_t bytes_read; + char *res; /* result */ + size_t res_len; char *cp; - int cc; /* bytes read, or -1 */ int savederr; /* saved errno */ - - *errnum = NULL; + *errfmt = NULL; if (!shellName) Shell_Init(); @@ -1653,7 +1641,7 @@ Cmd_Exec(const char *cmd, const char **errnum) * Open a pipe for fetching its output */ if (pipe(fds) == -1) { - *errnum = "Couldn't create pipe for \"%s\""; + *errfmt = "Couldn't create pipe for \"%s\""; goto bad; } @@ -1682,7 +1670,7 @@ Cmd_Exec(const char *cmd, const char **errnum) /*NOTREACHED*/ case -1: - *errnum = "Couldn't exec \"%s\""; + *errfmt = "Couldn't exec \"%s\""; goto bad; default: @@ -1696,12 +1684,12 @@ Cmd_Exec(const char *cmd, const char **errnum) do { char result[BUFSIZ]; - cc = read(fds[0], result, sizeof(result)); - if (cc > 0) - Buf_AddBytes(&buf, cc, result); + bytes_read = read(fds[0], result, sizeof(result)); + if (bytes_read > 0) + Buf_AddBytes(&buf, result, (size_t)bytes_read); } - while (cc > 0 || (cc == -1 && errno == EINTR)); - if (cc == -1) + while (bytes_read > 0 || (bytes_read == -1 && errno == EINTR)); + if (bytes_read == -1) savederr = errno; /* @@ -1716,43 +1704,28 @@ Cmd_Exec(const char *cmd, const char **errnum) JobReapChild(pid, status, FALSE); continue; } - cc = Buf_Size(&buf); + res_len = Buf_Size(&buf); res = Buf_Destroy(&buf, FALSE); if (savederr != 0) - *errnum = "Couldn't read shell's output for \"%s\""; + *errfmt = "Couldn't read shell's output for \"%s\""; if (WIFSIGNALED(status)) - *errnum = "\"%s\" exited on a signal"; + *errfmt = "\"%s\" exited on a signal"; else if (WEXITSTATUS(status) != 0) - *errnum = "\"%s\" returned non-zero status"; - - /* - * Null-terminate the result, convert newlines to spaces and - * install it in the variable. - */ - res[cc] = '\0'; - cp = &res[cc]; + *errfmt = "\"%s\" returned non-zero status"; - if (cc > 0 && *--cp == '\n') { - /* - * A final newline is just stripped - */ - *cp-- = '\0'; - } - while (cp >= res) { - if (*cp == '\n') { + /* Convert newlines to spaces. A final newline is just stripped */ + if (res_len > 0 && res[res_len - 1] == '\n') + res[res_len - 1] = '\0'; + for (cp = res; *cp != '\0'; cp++) + if (*cp == '\n') *cp = ' '; - } - cp--; - } break; } return res; bad: - res = bmake_malloc(1); - *res = '\0'; - return res; + return bmake_strdup(""); } /*- @@ -1888,7 +1861,7 @@ DieHorribly(void) */ void Finish(int errors) - /* number of errors encountered in Make_Make */ + /* number of errors encountered in Make_Make */ { if (dieQuietly(NULL, -1)) exit(2); @@ -1956,13 +1929,13 @@ usage(void) { char *p; if ((p = strchr(progname, '[')) != NULL) - *p = '\0'; + *p = '\0'; (void)fprintf(stderr, -"usage: %s [-BeikNnqrstWwX] \n\ - [-C directory] [-D variable] [-d flags] [-f makefile]\n\ - [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n\ - [-V variable] [-v variable] [variable=value] [target ...]\n", +"usage: %s [-BeikNnqrstWwX] \n" +" [-C directory] [-D variable] [-d flags] [-f makefile]\n" +" [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n" +" [-V variable] [-v variable] [variable=value] [target ...]\n", progname); exit(2); } @@ -2010,7 +1983,8 @@ char * cached_realpath(const char *pathname, char *resolved) { GNode *cache; - char *rp, *cp; + const char *rp; + char *cp; if (!pathname || !pathname[0]) return NULL; @@ -2024,7 +1998,7 @@ cached_realpath(const char *pathname, char *resolved) Var_Set(pathname, rp, cache); } /* else should we negative-cache? */ - free(cp); + bmake_free(cp); return rp ? resolved : NULL; } @@ -2070,9 +2044,14 @@ void PrintOnError(GNode *gn, const char *s) { static GNode *en = NULL; - char tmp[64]; + const char *expr; char *cp; + if (DEBUG(HASH)) { + Targ_Stats(); + Var_Stats(); + } + /* we generally want to keep quiet if a sub-make died */ if (dieQuietly(gn, -1)) return; @@ -2092,14 +2071,10 @@ PrintOnError(GNode *gn, const char *s) Var_Delete(".ERROR_CMD", VAR_GLOBAL); Lst_ForEach(gn->commands, addErrorCMD, gn); } - strncpy(tmp, "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}", - sizeof(tmp) - 1); - cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); - if (cp) { - if (*cp) - printf("%s", cp); - free(cp); - } + expr = "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}"; + cp = Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES); + printf("%s", cp); + free(cp); fflush(stdout); /* @@ -2115,18 +2090,17 @@ PrintOnError(GNode *gn, const char *s) void Main_ExportMAKEFLAGS(Boolean first) { - static int once = 1; - char tmp[64]; + static Boolean once = TRUE; + const char *expr; char *s; if (once != first) return; - once = 0; + once = FALSE; - strncpy(tmp, "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}", - sizeof(tmp)); - s = Var_Subst(NULL, tmp, VAR_CMD, VARF_WANTRES); - if (s && *s) { + expr = "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}"; + s = Var_Subst(expr, VAR_CMD, VARE_WANTRES); + if (s[0] != '\0') { #ifdef POSIX setenv("MAKEFLAGS", s, 1); #else @@ -2147,8 +2121,8 @@ getTmpdir(void) * Honor $TMPDIR but only if it is valid. * Ensure it ends with /. */ - tmpdir = Var_Subst(NULL, "${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, - VARF_WANTRES); + tmpdir = Var_Subst("${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, + VARE_WANTRES); if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { free(tmpdir); tmpdir = bmake_strdup(_PATH_TMP); @@ -2235,18 +2209,12 @@ s2Boolean(const char *s, Boolean bf) * is FALSE, otherwise TRUE. */ Boolean -getBoolean(const char *name, Boolean bf) +getBoolean(const char *name, Boolean fallback) { - char tmp[64]; - char *cp; - - if (snprintf(tmp, sizeof(tmp), "${%s:U:tl}", name) < (int)(sizeof(tmp))) { - cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); - - if (cp) { - bf = s2Boolean(cp, bf); - free(cp); - } - } - return bf; + char *expr = str_concat3("${", name, ":U:tl}"); + char *value = Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES); + Boolean res = s2Boolean(value, fallback); + free(value); + free(expr); + return res; } diff --git a/make-conf.h b/make-conf.h index a85b86d3efb5..5b13e295ae0c 100644 --- a/make-conf.h +++ b/make-conf.h @@ -1,4 +1,4 @@ -/* $NetBSD: config.h,v 1.21 2012/03/31 00:12:24 christos Exp $ */ +/* $NetBSD: config.h,v 1.22 2020/09/01 17:40:34 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -100,7 +100,10 @@ * LIBSUFF * Is the suffix used to denote libraries and is used by the Suff module * to find the search path on which to seek any -l<xx> targets. - * + */ +#define LIBSUFF ".a" + +/* * RECHECK * If defined, Make_Update will check a target for its current * modification time after it has been re-made, setting it to the @@ -108,10 +111,9 @@ * Unfortunately, under NFS the modification time often doesn't * get updated in time, so a target will appear to not have been * re-made, causing later targets to appear up-to-date. On systems - * that don't have this problem, you should defined this. Under + * that don't have this problem, you should define this. Under * NFS you probably should not, unless you aren't exporting jobs. */ -#define LIBSUFF ".a" #define RECHECK /* @@ -1,4 +1,4 @@ -.\" $NetBSD: make.1,v 1.282 2020/06/06 20:28:42 wiz Exp $ +.\" $NetBSD: make.1,v 1.289 2020/08/28 17:15:04 rillig Exp $ .\" .\" Copyright (c) 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" from: @(#)make.1 8.4 (Berkeley) 3/19/94 .\" -.Dd June 5, 2020 +.Dd August 28, 2020 .Dt MAKE 1 .Os .Sh NAME @@ -166,8 +166,15 @@ Print the input graph after making everything, or before exiting on error. .It Ar "g3" Print the input graph before exiting on error. +.It Ar h +Print debugging information about hash table operations. .It Ar j Print debugging information about running multiple shells. +.It Ar L +Turn on lint checks. +This will throw errors for variable assignments that do not parse +correctly, at the time of assignment so the file and line number +are available. .It Ar l Print commands in Makefiles regardless of whether or not they are prefixed by .Ql @ @@ -311,7 +318,8 @@ as an argument). .It Fl n Display the commands that would have been executed, but do not actually execute them unless the target depends on the .MAKE special -source (see below). +source (see below) or the command is prefixed with +.Ql Ic + . .It Fl N Display the commands which would have been executed, but do not actually execute any of them; useful for debugging top-level makefiles @@ -412,37 +420,44 @@ or more sources. This creates a relationship where the targets .Dq depend on the sources -and are usually created from them. -The exact relationship between the target and the source is determined -by the operator that separates them. -The three operators are as follows: +and are customarily created from them. +A target is considered out-of-date if it does not exist, or if its +modification time is less than that of any of its sources. +An out-of-date target will be re-created, but not until all sources +have been examined and themselves re-created as needed. +Three operators may be used: .Bl -tag -width flag .It Ic \&: -A target is considered out-of-date if its modification time is less than -those of any of its sources. -Sources for a target accumulate over dependency lines when this operator -is used. -The target is removed if +Many dependency lines may name this target but only one may have +attached shell commands. +All sources named in all dependency lines are considered together, +and if needed the attached shell commands are run to create or +re-create the target. +If .Nm -is interrupted. +is interrupted, the target is removed. .It Ic \&! -Targets are always re-created, but not until all sources have been -examined and re-created as necessary. -Sources for a target accumulate over dependency lines when this operator -is used. -The target is removed if -.Nm -is interrupted. +The same, but the target is always re-created whether or not it is out +of date. .It Ic \&:: -If no sources are specified, the target is always re-created. -Otherwise, a target is considered out-of-date if any of its sources has -been modified more recently than the target. -Sources for a target do not accumulate over dependency lines when this -operator is used. -The target will not be removed if +Any dependency line may have attached shell commands, but each one +is handled independently: its sources are considered and the attached +shell commands are run if the target is out of date with respect to +(only) those sources. +Thus, different groups of the attached shell commands may be run +depending on the circumstances. +Furthermore, unlike +.Ic \&:, +for dependency lines with no sources, the attached shell +commands are always run. +Also unlike +.Ic \&:, +the target will not be removed if .Nm is interrupted. .El +All dependency lines mentioning a particular target must use the same +operator. .Pp Targets and sources may contain the shell wildcard values .Ql \&? , @@ -608,7 +623,7 @@ This shorter form is not recommended. .Pp If the variable name contains a dollar, then the name itself is expanded first. This allows almost arbitrary variable names, however names containing dollar, -braces, parenthesis, or whitespace are really best avoided! +braces, parentheses, or whitespace are really best avoided! .Pp If the result of expanding a variable contains a dollar sign .Pq Ql \&$ @@ -1126,6 +1141,9 @@ is set to the value of for all programs which .Nm executes. +.It Ev .SHELL +The pathname of the shell used to run target scripts. +It is read-only. .It Ev .TARGETS The list of targets explicitly specified on the command line, if any. .It Ev VPATH @@ -1171,7 +1189,7 @@ Replaces each word in the variable with its suffix. .It Cm \&:H Replaces each word in the variable with everything but the last component. .It Cm \&:M Ns Ar pattern -Select only those words that match +Selects only those words that match .Ar pattern . The standard shell wildcard characters .Pf ( Ql * , @@ -1195,11 +1213,11 @@ This is identical to but selects all words which do not match .Ar pattern . .It Cm \&:O -Order every word in variable alphabetically. +Orders every word in variable alphabetically. .It Cm \&:Or -Order every word in variable in reverse alphabetical order. +Orders every word in variable in reverse alphabetical order. .It Cm \&:Ox -Randomize words in variable. +Shuffles the words in variable. The results will be different each time you are referring to the modified variable; use the assignment with expansion .Pq Ql Cm \&:= @@ -1249,7 +1267,7 @@ If a .Va utc value is not provided or is 0, the current time is used. .It Cm \&:hash -Compute a 32-bit hash of the value and encode it as hex digits. +Computes a 32-bit hash of the value and encode it as hex digits. .It Cm \&:localtime[=utc] The value is a format string for .Xr strftime 3 , @@ -1259,7 +1277,7 @@ If a .Va utc value is not provided or is 0, the current time is used. .It Cm \&:tA -Attempt to convert variable to an absolute path using +Attempts to convert variable to an absolute path using .Xr realpath 3 , if that fails, the value is unchanged. .It Cm \&:tl @@ -1271,7 +1289,7 @@ This modifier sets the separator to the character If .Ar c is omitted, then no separator is used. -The common escapes (including octal numeric codes), work as expected. +The common escapes (including octal numeric codes) work as expected. .It Cm \&:tu Converts variable to upper-case letters. .It Cm \&:tW @@ -1287,21 +1305,21 @@ See also .Sm off .It Cm \&:S No \&/ Ar old_string No \&/ Ar new_string No \&/ Op Cm 1gW .Sm on -Modify the first occurrence of +Modifies the first occurrence of .Ar old_string -in the variable's value, replacing it with +in each word of the variable's value, replacing it with .Ar new_string . If a .Ql g -is appended to the last slash of the pattern, all occurrences +is appended to the last delimiter of the pattern, all occurrences in each word are replaced. If a .Ql 1 -is appended to the last slash of the pattern, only the first word +is appended to the last delimiter of the pattern, only the first occurrence is affected. If a .Ql W -is appended to the last slash of the pattern, +is appended to the last delimiter of the pattern, then the value is treated as a single word (possibly containing embedded white space). If @@ -1370,13 +1388,6 @@ as occur in the word or words it is found in; the .Ql W modifier causes the value to be treated as a single word (possibly containing embedded white space). -Note that -.Ql 1 -and -.Ql g -are orthogonal; the former specifies whether multiple words are -potentially affected, the latter whether multiple substitutions can -potentially occur within each affected word. .Pp As for the .Cm \&:S @@ -1387,9 +1398,9 @@ and are subjected to variable expansion before being parsed as regular expressions. .It Cm \&:T -Replaces each word in the variable with its last component. +Replaces each word in the variable with its last path component. .It Cm \&:u -Remove adjacent duplicate words (like +Removes adjacent duplicate words (like .Xr uniq 1 ) . .Sm off .It Cm \&:\&? Ar true_string Cm \&: Ar false_string @@ -1405,7 +1416,7 @@ usually contain variable expansions. A common error is trying to use expressions like .Dl ${NUMBERS:M42:?match:no} which actually tests defined(NUMBERS), -to determine is any words match "42" you need to use something like: +to determine if any words match "42" you need to use something like: .Dl ${"${NUMBERS:M42}" != \&"\&":?match:no} . .It Ar :old_string=new_string This is the @@ -1449,7 +1460,7 @@ in either the or .Ar old_string , only the first instance is treated specially (as the pattern character); -all subsequent instances are treated as regular characters +all subsequent instances are treated as regular characters. .Pp Variable expansion occurs in the normal fashion inside both .Ar old_string @@ -1466,11 +1477,10 @@ This is the loop expansion mechanism from the OSF Development Environment (ODE) make. Unlike .Cm \&.for -loops expansion occurs at the time of -reference. -Assign +loops, expansion occurs at the time of reference. +Assigns .Ar temp -to each word in the variable and evaluate +to each word in the variable and evaluates .Ar string . The ODE convention is that .Ar temp @@ -1481,7 +1491,7 @@ For example. However a single character variable is often more readable: .Dl ${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'${.newline}@} .It Cm \&:_[=var] -Save the current variable value in +Saves the current variable value in .Ql $_ or the named .Va var @@ -1502,7 +1512,7 @@ is used to save the result of the modifier which is later referenced using the index values from .Ql :range . .It Cm \&:U Ns Ar newval -If the variable is undefined +If the variable is undefined, .Ar newval is the value. If the variable is defined, the existing value is returned. @@ -1512,7 +1522,7 @@ It is handy for setting per-target CFLAGS for instance: If a value is only required if the variable is undefined, use: .Dl ${VAR:D:Unewval} .It Cm \&:D Ns Ar newval -If the variable is defined +If the variable is defined, .Ar newval is the value. .It Cm \&:L @@ -1641,7 +1651,7 @@ Returns the number of words in the value. .El \" :[range] .El .Sh INCLUDE STATEMENTS, CONDITIONALS AND FOR LOOPS -Makefile inclusion, conditional structures and for loops reminiscent +Makefile inclusion, conditional structures and for loops reminiscent of the C programming language are provided in .Nm . All such structures are identified by a line beginning with a single @@ -1687,7 +1697,7 @@ The possible conditionals are as follows: The message is printed along with the name of the makefile and line number, then .Nm -will exit. +will exit immediately. .It Ic .export Ar variable ... Export the specified global variable. If no variable list is provided, all globals are exported @@ -1876,7 +1886,7 @@ operator is not an integral value, then string comparison is performed between the expanded variables. If no relational operator is given, it is assumed that the expanded -variable is being compared against 0 or an empty string in the case +variable is being compared against 0, or an empty string in the case of a string comparison. .Pp When @@ -1917,7 +1927,7 @@ The syntax of a for loop is: .Pp .Bl -tag -compact -width Ds .It Ic \&.for Ar variable Oo Ar variable ... Oc Ic in Ar expression -.It Aq make-rules +.It Aq make-lines .It Ic \&.endfor .El .Pp @@ -1929,7 +1939,7 @@ On each iteration of the loop, one word is taken and assigned to each in order, and these .Ic variables are substituted into the -.Ic make-rules +.Ic make-lines inside the body of the for loop. The number of words must come out even; that is, if there are three iteration variables, the number of words provided must be a multiple @@ -1,4 +1,4 @@ -/* $NetBSD: make.c,v 1.99 2020/07/03 08:13:23 rillig Exp $ */ +/* $NetBSD: make.c,v 1.133 2020/08/30 14:11:42 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -69,14 +69,14 @@ */ #ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: make.c,v 1.99 2020/07/03 08:13:23 rillig Exp $"; +static char rcsid[] = "$NetBSD: make.c,v 1.133 2020/08/30 14:11:42 rillig Exp $"; #else #include <sys/cdefs.h> #ifndef lint #if 0 static char sccsid[] = "@(#)make.c 8.1 (Berkeley) 6/6/93"; #else -__RCSID("$NetBSD: make.c,v 1.99 2020/07/03 08:13:23 rillig Exp $"); +__RCSID("$NetBSD: make.c,v 1.133 2020/08/30 14:11:42 rillig Exp $"); #endif #endif /* not lint */ #endif @@ -116,7 +116,7 @@ __RCSID("$NetBSD: make.c,v 1.99 2020/07/03 08:13:23 rillig Exp $"); */ #include "make.h" -#include "hash.h" +#include "enum.h" #include "dir.h" #include "job.h" @@ -151,6 +151,43 @@ make_abort(GNode *gn, int line) abort(); } +ENUM_VALUE_RTTI_8(GNodeMade, + UNMADE, DEFERRED, REQUESTED, BEINGMADE, + MADE, UPTODATE, ERROR, ABORTED); + +ENUM_FLAGS_RTTI_31(GNodeType, + OP_DEPENDS, OP_FORCE, OP_DOUBLEDEP, + /* OP_OPMASK is omitted since it combines other flags */ + OP_OPTIONAL, OP_USE, OP_EXEC, OP_IGNORE, + OP_PRECIOUS, OP_SILENT, OP_MAKE, OP_JOIN, + OP_MADE, OP_SPECIAL, OP_USEBEFORE, OP_INVISIBLE, + OP_NOTMAIN, OP_PHONY, OP_NOPATH, OP_WAIT, + OP_NOMETA, OP_META, OP_NOMETA_CMP, OP_SUBMAKE, + OP_TRANSFORM, OP_MEMBER, OP_LIB, OP_ARCHV, + OP_HAS_COMMANDS, OP_SAVE_CMDS, OP_DEPS_FOUND, OP_MARK); + +ENUM_FLAGS_RTTI_10(GNodeFlags, + REMAKE, CHILDMADE, FORCE, DONE_WAIT, + DONE_ORDER, FROM_DEPEND, DONE_ALLSRC, CYCLE, + DONECYCLE, INTERNAL); + +void +GNode_FprintDetails(FILE *f, const char *prefix, const GNode *gn, + const char *suffix) +{ + char type_buf[GNodeType_ToStringSize]; + char flags_buf[GNodeFlags_ToStringSize]; + + fprintf(f, "%smade %s, type %s, flags %s%s", + prefix, + Enum_ValueToString(gn->made, GNodeMade_ToStringSpecs), + Enum_FlagsToString(type_buf, sizeof type_buf, + gn->type, GNodeType_ToStringSpecs), + Enum_FlagsToString(flags_buf, sizeof flags_buf, + gn->flags, GNodeFlags_ToStringSpecs), + suffix); +} + /*- *----------------------------------------------------------------------- * Make_TimeStamp -- @@ -189,7 +226,7 @@ MakeTimeStamp(void *pgn, void *cgn) { return Make_TimeStamp((GNode *)pgn, (GNode *)cgn); } - + /*- *----------------------------------------------------------------------- * Make_OODate -- @@ -350,7 +387,7 @@ Make_OODate(GNode *gn) return oodate; } - + /*- *----------------------------------------------------------------------- * MakeAddChild -- @@ -378,11 +415,11 @@ MakeAddChild(void *gnp, void *lp) if (DEBUG(MAKE)) fprintf(debug_file, "MakeAddChild: need to examine %s%s\n", gn->name, gn->cohort_num); - (void)Lst_EnQueue(l, gn); + Lst_Enqueue(l, gn); } return 0; } - + /*- *----------------------------------------------------------------------- * MakeFindChild -- @@ -412,31 +449,18 @@ MakeFindChild(void *gnp, void *pgnp) return 0; } - -/*- - *----------------------------------------------------------------------- - * Make_HandleUse -- - * Function called by Make_Run and SuffApplyTransform on the downward - * pass to handle .USE and transformation nodes. It implements the - * .USE and transformation functionality by copying the node's commands, - * type flags and children to the parent node. + +/* Called by Make_Run and SuffApplyTransform on the downward pass to handle + * .USE and transformation nodes, by copying the child node's commands, type + * flags and children to the parent node. * - * A .USE node is much like an explicit transformation rule, except - * its commands are always added to the target node, even if the - * target already has commands. + * A .USE node is much like an explicit transformation rule, except its + * commands are always added to the target node, even if the target already + * has commands. * * Input: * cgn The .USE node * pgn The target of the .USE node - * - * Results: - * none - * - * Side Effects: - * Children and commands may be added to the parent and the parent's - * type may be changed. - * - *----------------------------------------------------------------------- */ void Make_HandleUse(GNode *cgn, GNode *pgn) @@ -452,52 +476,42 @@ Make_HandleUse(GNode *cgn, GNode *pgn) if ((cgn->type & (OP_USE|OP_USEBEFORE)) || Lst_IsEmpty(pgn->commands)) { if (cgn->type & OP_USEBEFORE) { - /* - * .USEBEFORE -- - * prepend the child's commands to the parent. - */ - Lst cmds = pgn->commands; - pgn->commands = Lst_Duplicate(cgn->commands, NULL); - (void)Lst_Concat(pgn->commands, cmds, LST_CONCNEW); - Lst_Destroy(cmds, NULL); + /* .USEBEFORE */ + Lst_PrependAll(pgn->commands, cgn->commands); } else { - /* - * .USE or target has no commands -- - * append the child's commands to the parent. - */ - (void)Lst_Concat(pgn->commands, cgn->commands, LST_CONCNEW); + /* .USE, or target has no commands */ + Lst_AppendAll(pgn->commands, cgn->commands); } } - if (Lst_Open(cgn->children) == SUCCESS) { - while ((ln = Lst_Next(cgn->children)) != NULL) { - GNode *tgn, *gn = (GNode *)Lst_Datum(ln); + Lst_Open(cgn->children); + while ((ln = Lst_Next(cgn->children)) != NULL) { + GNode *gn = LstNode_Datum(ln); - /* - * Expand variables in the .USE node's name - * and save the unexpanded form. - * We don't need to do this for commands. - * They get expanded properly when we execute. - */ - if (gn->uname == NULL) { - gn->uname = gn->name; - } else { - free(gn->name); - } - gn->name = Var_Subst(NULL, gn->uname, pgn, VARF_WANTRES); - if (gn->name && gn->uname && strcmp(gn->name, gn->uname) != 0) { - /* See if we have a target for this node. */ - tgn = Targ_FindNode(gn->name, TARG_NOCREATE); - if (tgn != NULL) - gn = tgn; - } - - (void)Lst_AtEnd(pgn->children, gn); - (void)Lst_AtEnd(gn->parents, pgn); - pgn->unmade += 1; + /* + * Expand variables in the .USE node's name + * and save the unexpanded form. + * We don't need to do this for commands. + * They get expanded properly when we execute. + */ + if (gn->uname == NULL) { + gn->uname = gn->name; + } else { + free(gn->name); } - Lst_Close(cgn->children); + gn->name = Var_Subst(gn->uname, pgn, VARE_WANTRES); + if (gn->uname && strcmp(gn->name, gn->uname) != 0) { + /* See if we have a target for this node. */ + GNode *tgn = Targ_FindNode(gn->name, TARG_NOCREATE); + if (tgn != NULL) + gn = tgn; + } + + Lst_Append(pgn->children, gn); + Lst_Append(gn->parents, pgn); + pgn->unmade += 1; } + Lst_Close(cgn->children); pgn->type |= cgn->type & ~(OP_OPMASK|OP_USE|OP_USEBEFORE|OP_TRANSFORM); } @@ -547,7 +561,7 @@ MakeHandleUse(void *cgnp, void *pgnp) * children the parent has. This is used by Make_Run to decide * whether to queue the parent or examine its children... */ - if ((ln = Lst_Member(pgn->children, cgn)) != NULL) { + if ((ln = Lst_FindDatum(pgn->children, cgn)) != NULL) { Lst_Remove(pgn->children, ln); pgn->unmade--; } @@ -680,8 +694,8 @@ void Make_Update(GNode *cgn) { GNode *pgn; /* the parent node */ - char *cname; /* the child's name */ - LstNode ln; /* Element in parents and iParents lists */ + const char *cname; /* the child's name */ + LstNode ln; /* Element in parents and implicitParents lists */ time_t mtime = -1; char *p1; Lst parents; @@ -691,7 +705,7 @@ Make_Update(GNode *cgn) checked++; cname = Var_Value(TARGET, cgn, &p1); - free(p1); + bmake_free(p1); if (DEBUG(MAKE)) fprintf(debug_file, "Make_Update: %s%s\n", cgn->name, cgn->cohort_num); @@ -724,123 +738,123 @@ Make_Update(GNode *cgn) Lst_ForEach(centurion->order_succ, MakeBuildParent, Lst_First(toBeMade)); /* Now mark all the parents as having one less unmade child */ - if (Lst_Open(parents) == SUCCESS) { - while ((ln = Lst_Next(parents)) != NULL) { - pgn = (GNode *)Lst_Datum(ln); - if (DEBUG(MAKE)) - fprintf(debug_file, "inspect parent %s%s: flags %x, " - "type %x, made %d, unmade %d ", - pgn->name, pgn->cohort_num, pgn->flags, - pgn->type, pgn->made, pgn->unmade-1); - - if (!(pgn->flags & REMAKE)) { - /* This parent isn't needed */ - if (DEBUG(MAKE)) - fprintf(debug_file, "- not needed\n"); - continue; - } - if (mtime == 0 && !(cgn->type & OP_WAIT)) - pgn->flags |= FORCE; + Lst_Open(parents); + while ((ln = Lst_Next(parents)) != NULL) { + pgn = LstNode_Datum(ln); + if (DEBUG(MAKE)) + fprintf(debug_file, "inspect parent %s%s: flags %x, " + "type %x, made %d, unmade %d ", + pgn->name, pgn->cohort_num, pgn->flags, + pgn->type, pgn->made, pgn->unmade-1); - /* - * If the parent has the .MADE attribute, its timestamp got - * updated to that of its newest child, and its unmake - * child count got set to zero in Make_ExpandUse(). - * However other things might cause us to build one of its - * children - and so we mustn't do any processing here when - * the child build finishes. - */ - if (pgn->type & OP_MADE) { - if (DEBUG(MAKE)) - fprintf(debug_file, "- .MADE\n"); - continue; - } + if (!(pgn->flags & REMAKE)) { + /* This parent isn't needed */ + if (DEBUG(MAKE)) + fprintf(debug_file, "- not needed\n"); + continue; + } + if (mtime == 0 && !(cgn->type & OP_WAIT)) + pgn->flags |= FORCE; - if ( ! (cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE))) { - if (cgn->made == MADE) - pgn->flags |= CHILDMADE; - (void)Make_TimeStamp(pgn, cgn); - } + /* + * If the parent has the .MADE attribute, its timestamp got + * updated to that of its newest child, and its unmake + * child count got set to zero in Make_ExpandUse(). + * However other things might cause us to build one of its + * children - and so we mustn't do any processing here when + * the child build finishes. + */ + if (pgn->type & OP_MADE) { + if (DEBUG(MAKE)) + fprintf(debug_file, "- .MADE\n"); + continue; + } - /* - * A parent must wait for the completion of all instances - * of a `::' dependency. - */ - if (centurion->unmade_cohorts != 0 || centurion->made < MADE) { - if (DEBUG(MAKE)) - fprintf(debug_file, - "- centurion made %d, %d unmade cohorts\n", - centurion->made, centurion->unmade_cohorts); - continue; - } + if ( ! (cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE))) { + if (cgn->made == MADE) + pgn->flags |= CHILDMADE; + (void)Make_TimeStamp(pgn, cgn); + } - /* One more child of this parent is now made */ - pgn->unmade -= 1; - if (pgn->unmade < 0) { - if (DEBUG(MAKE)) { - fprintf(debug_file, "Graph cycles through %s%s\n", - pgn->name, pgn->cohort_num); - Targ_PrintGraph(2); - } - Error("Graph cycles through %s%s", pgn->name, pgn->cohort_num); - } + /* + * A parent must wait for the completion of all instances + * of a `::' dependency. + */ + if (centurion->unmade_cohorts != 0 || centurion->made < MADE) { + if (DEBUG(MAKE)) + fprintf(debug_file, + "- centurion made %d, %d unmade cohorts\n", + centurion->made, centurion->unmade_cohorts); + continue; + } - /* We must always rescan the parents of .WAIT and .ORDER nodes. */ - if (pgn->unmade != 0 && !(centurion->type & OP_WAIT) - && !(centurion->flags & DONE_ORDER)) { - if (DEBUG(MAKE)) - fprintf(debug_file, "- unmade children\n"); - continue; - } - if (pgn->made != DEFERRED) { - /* - * Either this parent is on a different branch of the tree, - * or it on the RHS of a .WAIT directive - * or it is already on the toBeMade list. - */ - if (DEBUG(MAKE)) - fprintf(debug_file, "- not deferred\n"); - continue; - } - if (pgn->order_pred - && Lst_ForEach(pgn->order_pred, MakeCheckOrder, 0)) { - /* A .ORDER rule stops us building this */ - continue; - } + /* One more child of this parent is now made */ + pgn->unmade -= 1; + if (pgn->unmade < 0) { if (DEBUG(MAKE)) { - static int two = 2; - fprintf(debug_file, "- %s%s made, schedule %s%s (made %d)\n", - cgn->name, cgn->cohort_num, - pgn->name, pgn->cohort_num, pgn->made); - Targ_PrintNode(pgn, &two); + fprintf(debug_file, "Graph cycles through %s%s\n", + pgn->name, pgn->cohort_num); + Targ_PrintGraph(2); } - /* Ok, we can schedule the parent again */ - pgn->made = REQUESTED; - (void)Lst_EnQueue(toBeMade, pgn); + Error("Graph cycles through %s%s", pgn->name, pgn->cohort_num); + } + + /* We must always rescan the parents of .WAIT and .ORDER nodes. */ + if (pgn->unmade != 0 && !(centurion->type & OP_WAIT) + && !(centurion->flags & DONE_ORDER)) { + if (DEBUG(MAKE)) + fprintf(debug_file, "- unmade children\n"); + continue; + } + if (pgn->made != DEFERRED) { + /* + * Either this parent is on a different branch of the tree, + * or it on the RHS of a .WAIT directive + * or it is already on the toBeMade list. + */ + if (DEBUG(MAKE)) + fprintf(debug_file, "- not deferred\n"); + continue; } - Lst_Close(parents); + assert(pgn->order_pred != NULL); + if (Lst_ForEach(pgn->order_pred, MakeCheckOrder, 0)) { + /* A .ORDER rule stops us building this */ + continue; + } + if (DEBUG(MAKE)) { + static int two = 2; + fprintf(debug_file, "- %s%s made, schedule %s%s (made %d)\n", + cgn->name, cgn->cohort_num, + pgn->name, pgn->cohort_num, pgn->made); + Targ_PrintNode(pgn, &two); + } + /* Ok, we can schedule the parent again */ + pgn->made = REQUESTED; + Lst_Enqueue(toBeMade, pgn); } + Lst_Close(parents); /* * Set the .PREFIX and .IMPSRC variables for all the implied parents * of this node. */ - if (Lst_Open(cgn->iParents) == SUCCESS) { - char *cpref = Var_Value(PREFIX, cgn, &p1); + Lst_Open(cgn->implicitParents); + { + const char *cpref = Var_Value(PREFIX, cgn, &p1); - while ((ln = Lst_Next(cgn->iParents)) != NULL) { - pgn = (GNode *)Lst_Datum(ln); + while ((ln = Lst_Next(cgn->implicitParents)) != NULL) { + pgn = LstNode_Datum(ln); if (pgn->flags & REMAKE) { Var_Set(IMPSRC, cname, pgn); if (cpref != NULL) Var_Set(PREFIX, cpref, pgn); } } - free(p1); - Lst_Close(cgn->iParents); + bmake_free(p1); + Lst_Close(cgn->implicitParents); } } - + /*- *----------------------------------------------------------------------- * MakeAddAllSrc -- @@ -890,7 +904,7 @@ MakeAddAllSrc(void *cgnp, void *pgnp) cgn->type |= OP_MARK; if ((cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE|OP_INVISIBLE)) == 0) { - char *child, *allsrc; + const char *child, *allsrc; char *p1 = NULL, *p2 = NULL; if (cgn->type & OP_ARCHV) @@ -904,7 +918,7 @@ MakeAddAllSrc(void *cgnp, void *pgnp) } if (allsrc != NULL) Var_Append(ALLSRC, allsrc, pgn); - free(p2); + bmake_free(p2); if (pgn->type & OP_JOIN) { if (cgn->made == MADE) { Var_Append(OODATE, child, pgn); @@ -930,11 +944,11 @@ MakeAddAllSrc(void *cgnp, void *pgnp) */ Var_Append(OODATE, child, pgn); } - free(p1); + bmake_free(p1); } return 0; } - + /*- *----------------------------------------------------------------------- * Make_DoAllVar -- @@ -976,11 +990,11 @@ Make_DoAllVar(GNode *gn) if (gn->type & OP_JOIN) { char *p1; Var_Set(TARGET, Var_Value(ALLSRC, gn, &p1), gn); - free(p1); + bmake_free(p1); } gn->flags |= DONE_ALLSRC; } - + /*- *----------------------------------------------------------------------- * MakeStartJobs -- @@ -1023,7 +1037,8 @@ MakeBuildChild(void *v_cn, void *toBeMade_next) return 0; /* If this node is on the RHS of a .ORDER, check LHSs. */ - if (cn->order_pred && Lst_ForEach(cn->order_pred, MakeCheckOrder, 0)) { + assert(cn->order_pred); + if (Lst_ForEach(cn->order_pred, MakeCheckOrder, 0)) { /* Can't build this (or anything else in this child list) yet */ cn->made = DEFERRED; return 0; /* but keep looking */ @@ -1035,7 +1050,7 @@ MakeBuildChild(void *v_cn, void *toBeMade_next) cn->made = REQUESTED; if (toBeMade_next == NULL) - Lst_AtEnd(toBeMade, cn); + Lst_Append(toBeMade, cn); else Lst_InsertBefore(toBeMade, toBeMade_next, cn); @@ -1072,13 +1087,13 @@ MakeStartJobs(void) GNode *gn; int have_token = 0; - while (!Lst_IsEmpty (toBeMade)) { + while (!Lst_IsEmpty(toBeMade)) { /* Get token now to avoid cycling job-list when we only have 1 token */ if (!have_token && !Job_TokenWithdraw()) break; have_token = 1; - gn = (GNode *)Lst_DeQueue(toBeMade); + gn = Lst_Dequeue(toBeMade); if (DEBUG(MAKE)) fprintf(debug_file, "Examining %s%s...\n", gn->name, gn->cohort_num); @@ -1147,7 +1162,7 @@ MakeStartJobs(void) return FALSE; } - + /*- *----------------------------------------------------------------------- * MakePrintStatus -- @@ -1179,15 +1194,15 @@ MakePrintStatusOrder(void *ognp, void *gnp) /* not waiting for this one */ return 0; - printf(" `%s%s' has .ORDER dependency against %s%s " - "(made %d, flags %x, type %x)\n", - gn->name, gn->cohort_num, - ogn->name, ogn->cohort_num, ogn->made, ogn->flags, ogn->type); - if (DEBUG(MAKE) && debug_file != stdout) - fprintf(debug_file, " `%s%s' has .ORDER dependency against %s%s " - "(made %d, flags %x, type %x)\n", - gn->name, gn->cohort_num, - ogn->name, ogn->cohort_num, ogn->made, ogn->flags, ogn->type); + printf(" `%s%s' has .ORDER dependency against %s%s ", + gn->name, gn->cohort_num, ogn->name, ogn->cohort_num); + GNode_FprintDetails(stdout, "(", ogn, ")\n"); + + if (DEBUG(MAKE) && debug_file != stdout) { + fprintf(debug_file, " `%s%s' has .ORDER dependency against %s%s ", + gn->name, gn->cohort_num, ogn->name, ogn->cohort_num); + GNode_FprintDetails(debug_file, "(", ogn, ")\n"); + } return 0; } @@ -1214,12 +1229,13 @@ MakePrintStatus(void *gnp, void *v_errors) case REQUESTED: case BEINGMADE: (*errors)++; - printf("`%s%s' was not built (made %d, flags %x, type %x)!\n", - gn->name, gn->cohort_num, gn->made, gn->flags, gn->type); - if (DEBUG(MAKE) && debug_file != stdout) - fprintf(debug_file, - "`%s%s' was not built (made %d, flags %x, type %x)!\n", - gn->name, gn->cohort_num, gn->made, gn->flags, gn->type); + printf("`%s%s' was not built", gn->name, gn->cohort_num); + GNode_FprintDetails(stdout, " (", gn, ")!\n"); + if (DEBUG(MAKE) && debug_file != stdout) { + fprintf(debug_file, "`%s%s' was not built", + gn->name, gn->cohort_num); + GNode_FprintDetails(debug_file, " (", gn, ")!\n"); + } /* Most likely problem is actually caused by .ORDER */ Lst_ForEach(gn->order_pred, MakePrintStatusOrder, gn); break; @@ -1262,7 +1278,7 @@ MakePrintStatus(void *gnp, void *v_errors) Lst_ForEach(gn->children, MakePrintStatus, errors); return 0; } - + /*- *----------------------------------------------------------------------- @@ -1281,7 +1297,7 @@ Make_ExpandUse(Lst targs) GNode *gn; /* a temporary pointer */ Lst examine; /* List of targets to examine */ - examine = Lst_Duplicate(targs, NULL); + examine = Lst_Copy(targs, NULL); /* * Make an initial downward pass over the graph, marking nodes to be made @@ -1291,8 +1307,8 @@ Make_ExpandUse(Lst targs) * be looked at in a minute, otherwise we add its children to our queue * and go on about our business. */ - while (!Lst_IsEmpty (examine)) { - gn = (GNode *)Lst_DeQueue(examine); + while (!Lst_IsEmpty(examine)) { + gn = Lst_Dequeue(examine); if (gn->flags & REMAKE) /* We've looked at this one already */ @@ -1302,13 +1318,8 @@ Make_ExpandUse(Lst targs) fprintf(debug_file, "Make_ExpandUse: examine %s%s\n", gn->name, gn->cohort_num); - if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (gn->cohorts)) { - /* Append all the 'cohorts' to the list of things to examine */ - Lst new; - new = Lst_Duplicate(gn->cohorts, NULL); - Lst_Concat(new, examine, LST_CONCLINK); - examine = new; - } + if (gn->type & OP_DOUBLEDEP) + Lst_PrependAll(examine, gn->cohorts); /* * Apply any .USE rules before looking for implicit dependencies @@ -1349,7 +1360,7 @@ Make_ExpandUse(Lst targs) Lst_ForEach(gn->children, MakeAddChild, examine); } - Lst_Destroy(examine, NULL); + Lst_Free(examine); } /*- @@ -1369,8 +1380,8 @@ link_parent(void *cnp, void *pnp) GNode *cn = cnp; GNode *pn = pnp; - Lst_AtEnd(pn->children, cn); - Lst_AtEnd(cn->parents, pn); + Lst_Append(pn->children, cn); + Lst_Append(cn->parents, pn); pn->unmade++; return 0; } @@ -1392,9 +1403,9 @@ add_wait_dep(void *v_cn, void *v_wn) fprintf(debug_file, ".WAIT: add dependency %s%s -> %s\n", cn->name, cn->cohort_num, wn->name); - Lst_AtEnd(wn->children, cn); + Lst_Append(wn->children, cn); wn->unmade++; - Lst_AtEnd(cn->parents, wn); + Lst_Append(cn->parents, wn); return 0; } @@ -1417,18 +1428,18 @@ Make_ProcessWait(Lst targs) pgn->flags = REMAKE; pgn->type = OP_PHONY | OP_DEPENDS; /* Get it displayed in the diag dumps */ - Lst_AtFront(Targ_List(), pgn); + Lst_Prepend(Targ_List(), pgn); Lst_ForEach(targs, link_parent, pgn); /* Start building with the 'dummy' .MAIN' node */ MakeBuildChild(pgn, NULL); - examine = Lst_Init(FALSE); - Lst_AtEnd(examine, pgn); + examine = Lst_Init(); + Lst_Append(examine, pgn); - while (!Lst_IsEmpty (examine)) { - pgn = Lst_DeQueue(examine); + while (!Lst_IsEmpty(examine)) { + pgn = Lst_Dequeue(examine); /* We only want to process each child-list once */ if (pgn->flags & DONE_WAIT) @@ -1437,30 +1448,25 @@ Make_ProcessWait(Lst targs) if (DEBUG(MAKE)) fprintf(debug_file, "Make_ProcessWait: examine %s\n", pgn->name); - if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (pgn->cohorts)) { - /* Append all the 'cohorts' to the list of things to examine */ - Lst new; - new = Lst_Duplicate(pgn->cohorts, NULL); - Lst_Concat(new, examine, LST_CONCLINK); - examine = new; - } + if (pgn->type & OP_DOUBLEDEP) + Lst_PrependAll(examine, pgn->cohorts); owln = Lst_First(pgn->children); Lst_Open(pgn->children); for (; (ln = Lst_Next(pgn->children)) != NULL; ) { - cgn = Lst_Datum(ln); + cgn = LstNode_Datum(ln); if (cgn->type & OP_WAIT) { /* Make the .WAIT node depend on the previous children */ Lst_ForEachFrom(pgn->children, owln, add_wait_dep, cgn); owln = ln; } else { - Lst_AtEnd(examine, cgn); + Lst_Append(examine, cgn); } } Lst_Close(pgn->children); } - Lst_Destroy(examine, NULL); + Lst_Free(examine); } /*- @@ -1493,7 +1499,7 @@ Make_Run(Lst targs) int errors; /* Number of errors the Job module reports */ /* Start trying to make the current targets... */ - toBeMade = Lst_Init(FALSE); + toBeMade = Lst_Init(); Make_ExpandUse(targs); Make_ProcessWait(targs); @@ -1,4 +1,4 @@ -/* $NetBSD: make.h,v 1.109 2020/07/02 15:14:38 rillig Exp $ */ +/* $NetBSD: make.h,v 1.137 2020/09/02 23:42:58 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -77,8 +77,8 @@ * The global definitions for pmake */ -#ifndef _MAKE_H_ -#define _MAKE_H_ +#ifndef MAKE_MAKE_H +#define MAKE_MAKE_H #ifdef HAVE_CONFIG_H # include "config.h" @@ -86,7 +86,9 @@ #include <sys/types.h> #include <sys/param.h> +#include <sys/stat.h> +#include <assert.h> #include <ctype.h> #include <fcntl.h> #include <stdio.h> @@ -132,8 +134,34 @@ #define MAKE_ATTR_PRINTFLIKE(fmtarg, firstvararg) /* delete */ #endif -#include "sprite.h" +/* + * A boolean type is defined as an integer, not an enum, for historic reasons. + * The only allowed values are the constants TRUE and FALSE (1 and 0). + */ + +#ifdef USE_DOUBLE_BOOLEAN +/* During development, to find type mismatches in function declarations. */ +typedef double Boolean; +#elif defined(USE_UCHAR_BOOLEAN) +/* During development, to find code that depends on the exact value of TRUE or + * that stores other values in Boolean variables. */ +typedef unsigned char Boolean; +#define TRUE ((unsigned char)0xFF) +#define FALSE ((unsigned char)0x00) +#elif defined(USE_ENUM_BOOLEAN) +typedef enum { FALSE, TRUE} Boolean; +#else +typedef int Boolean; +#endif +#ifndef TRUE +#define TRUE 1 +#endif /* TRUE */ +#ifndef FALSE +#define FALSE 0 +#endif /* FALSE */ + #include "lst.h" +#include "enum.h" #include "hash.h" #include "make-conf.h" #include "buf.h" @@ -150,164 +178,191 @@ #define POSIX_SIGNALS #endif -/*- - * The structure for an individual graph node. Each node has several - * pieces of data associated with it. - * 1) the name of the target it describes - * 2) the location of the target file in the file system. - * 3) the type of operator used to define its sources (qv. parse.c) - * 4) whether it is involved in this invocation of make - * 5) whether the target has been remade - * 6) whether any of its children has been remade - * 7) the number of its children that are, as yet, unmade - * 8) its modification time - * 9) the modification time of its youngest child (qv. make.c) - * 10) a list of nodes for which this is a source (parents) - * 11) a list of nodes on which this depends (children) - * 12) a list of nodes that depend on this, as gleaned from the - * transformation rules (iParents) - * 13) a list of ancestor nodes, which includes parents, iParents, - * and recursive parents of parents - * 14) a list of nodes of the same name created by the :: operator - * 15) a list of nodes that must be made (if they're made) before - * this node can be, but that do not enter into the datedness of - * this node. - * 16) a list of nodes that must be made (if they're made) before - * this node or any child of this node can be, but that do not - * enter into the datedness of this node. - * 17) a list of nodes that must be made (if they're made) after - * this node is, but that do not depend on this node, in the - * normal sense. - * 18) a Lst of ``local'' variables that are specific to this target - * and this target only (qv. var.c [$@ $< $?, etc.]) - * 19) a Lst of strings that are commands to be given to a shell - * to create this target. - */ +typedef enum { + UNMADE, /* Not examined yet */ + DEFERRED, /* Examined once (building child) */ + REQUESTED, /* on toBeMade list */ + BEINGMADE, /* Target is already being made. + * Indicates a cycle in the graph. */ + MADE, /* Was out-of-date and has been made */ + UPTODATE, /* Was already up-to-date */ + ERROR, /* An error occurred while it was being + * made (used only in compat mode) */ + ABORTED /* The target was aborted due to an error + * making an inferior (compat). */ +} GNodeMade; + +/* The OP_ constants are used when parsing a dependency line as a way of + * communicating to other parts of the program the way in which a target + * should be made. + * + * These constants are bitwise-OR'ed together and placed in the 'type' field + * of each node. Any node that has a 'type' field which satisfies the OP_NOP + * function was never never on the left-hand side of an operator, though it + * may have been on the right-hand side... */ +typedef enum { + /* Execution of commands depends on children (:) */ + OP_DEPENDS = 1 << 0, + /* Always execute commands (!) */ + OP_FORCE = 1 << 1, + /* Execution of commands depends on children per line (::) */ + OP_DOUBLEDEP = 1 << 2, + + OP_OPMASK = OP_DEPENDS|OP_FORCE|OP_DOUBLEDEP, + + /* Don't care if the target doesn't exist and can't be created */ + OP_OPTIONAL = 1 << 3, + /* Use associated commands for parents */ + OP_USE = 1 << 4, + /* Target is never out of date, but always execute commands anyway. + * Its time doesn't matter, so it has none...sort of */ + OP_EXEC = 1 << 5, + /* Ignore errors when creating the node */ + OP_IGNORE = 1 << 6, + /* Don't remove the target when interrupted */ + OP_PRECIOUS = 1 << 7, + /* Don't echo commands when executed */ + OP_SILENT = 1 << 8, + /* Target is a recursive make so its commands should always be executed + * when it is out of date, regardless of the state of the -n or -t flags */ + OP_MAKE = 1 << 9, + /* Target is out-of-date only if any of its children was out-of-date */ + OP_JOIN = 1 << 10, + /* Assume the children of the node have been already made */ + OP_MADE = 1 << 11, + /* Special .BEGIN, .END, .INTERRUPT */ + OP_SPECIAL = 1 << 12, + /* Like .USE, only prepend commands */ + OP_USEBEFORE = 1 << 13, + /* The node is invisible to its parents. I.e. it doesn't show up in the + * parents' local variables. */ + OP_INVISIBLE = 1 << 14, + /* The node is exempt from normal 'main target' processing in parse.c */ + OP_NOTMAIN = 1 << 15, + /* Not a file target; run always */ + OP_PHONY = 1 << 16, + /* Don't search for file in the path */ + OP_NOPATH = 1 << 17, + /* .WAIT phony node */ + OP_WAIT = 1 << 18, + /* .NOMETA do not create a .meta file */ + OP_NOMETA = 1 << 19, + /* .META we _do_ want a .meta file */ + OP_META = 1 << 20, + /* Do not compare commands in .meta file */ + OP_NOMETA_CMP = 1 << 21, + /* Possibly a submake node */ + OP_SUBMAKE = 1 << 22, + + /* Attributes applied by PMake */ + + /* The node is a transformation rule */ + OP_TRANSFORM = 1 << 31, + /* Target is a member of an archive */ + OP_MEMBER = 1 << 30, + /* Target is a library */ + OP_LIB = 1 << 29, + /* Target is an archive construct */ + OP_ARCHV = 1 << 28, + /* Target has all the commands it should. Used when parsing to catch + * multiple commands for a target. */ + OP_HAS_COMMANDS = 1 << 27, + /* Saving commands on .END (Compat) */ + OP_SAVE_CMDS = 1 << 26, + /* Already processed by Suff_FindDeps */ + OP_DEPS_FOUND = 1 << 25, + /* Node found while expanding .ALLSRC */ + OP_MARK = 1 << 24 +} GNodeType; + +typedef enum { + REMAKE = 0x0001, /* this target needs to be (re)made */ + CHILDMADE = 0x0002, /* children of this target were made */ + FORCE = 0x0004, /* children don't exist, and we pretend made */ + DONE_WAIT = 0x0008, /* Set by Make_ProcessWait() */ + DONE_ORDER = 0x0010, /* Build requested by .ORDER processing */ + FROM_DEPEND = 0x0020, /* Node created from .depend */ + DONE_ALLSRC = 0x0040, /* We do it once only */ + CYCLE = 0x1000, /* Used by MakePrintStatus */ + DONECYCLE = 0x2000, /* Used by MakePrintStatus */ + INTERNAL = 0x4000 /* Internal use only */ +} GNodeFlags; + +/* A graph node represents a target that can possibly be made, including its + * relation to other targets and a lot of other details. */ typedef struct GNode { - char *name; /* The target's name */ - char *uname; /* The unexpanded name of a .USE node */ - char *path; /* The full pathname of the file */ - int type; /* Its type (see the OP flags, below) */ - - int flags; -#define REMAKE 0x1 /* this target needs to be (re)made */ -#define CHILDMADE 0x2 /* children of this target were made */ -#define FORCE 0x4 /* children don't exist, and we pretend made */ -#define DONE_WAIT 0x8 /* Set by Make_ProcessWait() */ -#define DONE_ORDER 0x10 /* Build requested by .ORDER processing */ -#define FROM_DEPEND 0x20 /* Node created from .depend */ -#define DONE_ALLSRC 0x40 /* We do it once only */ -#define CYCLE 0x1000 /* Used by MakePrintStatus */ -#define DONECYCLE 0x2000 /* Used by MakePrintStatus */ -#define INTERNAL 0x4000 /* Internal use only */ - enum enum_made { - UNMADE, DEFERRED, REQUESTED, BEINGMADE, - MADE, UPTODATE, ERROR, ABORTED - } made; /* Set to reflect the state of processing - * on this node: - * UNMADE - Not examined yet - * DEFERRED - Examined once (building child) - * REQUESTED - on toBeMade list - * BEINGMADE - Target is already being made. - * Indicates a cycle in the graph. - * MADE - Was out-of-date and has been made - * UPTODATE - Was already up-to-date - * ERROR - An error occurred while it was being - * made (used only in compat mode) - * ABORTED - The target was aborted due to - * an error making an inferior (compat). - */ - int unmade; /* The number of unmade children */ - - time_t mtime; /* Its modification time */ - struct GNode *cmgn; /* The youngest child */ - - Lst iParents; /* Links to parents for which this is an - * implied source, if any */ - Lst cohorts; /* Other nodes for the :: operator */ - Lst parents; /* Nodes that depend on this one */ - Lst children; /* Nodes on which this one depends */ - Lst order_pred; /* .ORDER nodes we need made */ - Lst order_succ; /* .ORDER nodes who need us */ - - char cohort_num[8]; /* #n for this cohort */ - int unmade_cohorts;/* # of unmade instances on the - cohorts list */ - struct GNode *centurion; /* Pointer to the first instance of a :: - node; only set when on a cohorts list */ - unsigned int checked; /* Last time we tried to makle this node */ - - Hash_Table context; /* The local variables */ - Lst commands; /* Creation commands */ - - struct _Suff *suffix; /* Suffix for the node (determined by - * Suff_FindDeps and opaque to everyone - * but the Suff module) */ - const char *fname; /* filename where the GNode got defined */ - int lineno; /* line number where the GNode got defined */ + /* The target's name, such as "clean" or "make.c" */ + char *name; + /* The unexpanded name of a .USE node */ + char *uname; + /* The full pathname of the file belonging to the target. + * XXX: What about .PHONY targets? These don't have an associated path. */ + char *path; + + /* The type of operator used to define the sources (see the OP flags below). + * XXX: This looks like a wild mixture of type and flags. */ + GNodeType type; + /* whether it is involved in this invocation of make */ + GNodeFlags flags; + + /* The state of processing on this node */ + GNodeMade made; + int unmade; /* The number of unmade children */ + + time_t mtime; /* Its modification time */ + struct GNode *cmgn; /* The youngest child */ + + /* The GNodes for which this node is an implied source. May be empty. + * For example, when there is an inference rule for .c.o, the node for + * file.c has the node for file.o in this list. */ + Lst implicitParents; + + /* Other nodes of the same name for the :: operator. */ + Lst cohorts; + + /* The nodes that depend on this one, or in other words, the nodes for + * which this is a source. */ + Lst parents; + /* The nodes on which this one depends. */ + Lst children; + + /* .ORDER nodes we need made. The nodes that must be made (if they're + * made) before this node can be made, but that do not enter into the + * datedness of this node. */ + Lst order_pred; + /* .ORDER nodes who need us. The nodes that must be made (if they're made + * at all) after this node is made, but that do not depend on this node, + * in the normal sense. */ + Lst order_succ; + + /* #n for this cohort */ + char cohort_num[8]; + /* The number of unmade instances on the cohorts list */ + int unmade_cohorts; + /* Pointer to the first instance of a '::' node; only set when on a + * cohorts list */ + struct GNode *centurion; + + /* Last time (sequence number) we tried to make this node */ + unsigned int checked; + + /* The "local" variables that are specific to this target and this target + * only, such as $@, $<, $?. */ + Hash_Table context; + + /* The commands to be given to a shell to create this target. */ + Lst commands; + + /* Suffix for the node (determined by Suff_FindDeps and opaque to everyone + * but the Suff module) */ + struct Suff *suffix; + + /* filename where the GNode got defined */ + const char *fname; + /* line number where the GNode got defined */ + int lineno; } GNode; -/* - * The OP_ constants are used when parsing a dependency line as a way of - * communicating to other parts of the program the way in which a target - * should be made. These constants are bitwise-OR'ed together and - * placed in the 'type' field of each node. Any node that has - * a 'type' field which satisfies the OP_NOP function was never never on - * the lefthand side of an operator, though it may have been on the - * righthand side... - */ -#define OP_DEPENDS 0x00000001 /* Execution of commands depends on - * kids (:) */ -#define OP_FORCE 0x00000002 /* Always execute commands (!) */ -#define OP_DOUBLEDEP 0x00000004 /* Execution of commands depends on kids - * per line (::) */ -#define OP_OPMASK (OP_DEPENDS|OP_FORCE|OP_DOUBLEDEP) - -#define OP_OPTIONAL 0x00000008 /* Don't care if the target doesn't - * exist and can't be created */ -#define OP_USE 0x00000010 /* Use associated commands for parents */ -#define OP_EXEC 0x00000020 /* Target is never out of date, but always - * execute commands anyway. Its time - * doesn't matter, so it has none...sort - * of */ -#define OP_IGNORE 0x00000040 /* Ignore errors when creating the node */ -#define OP_PRECIOUS 0x00000080 /* Don't remove the target when - * interrupted */ -#define OP_SILENT 0x00000100 /* Don't echo commands when executed */ -#define OP_MAKE 0x00000200 /* Target is a recursive make so its - * commands should always be executed when - * it is out of date, regardless of the - * state of the -n or -t flags */ -#define OP_JOIN 0x00000400 /* Target is out-of-date only if any of its - * children was out-of-date */ -#define OP_MADE 0x00000800 /* Assume the children of the node have - * been already made */ -#define OP_SPECIAL 0x00001000 /* Special .BEGIN, .END, .INTERRUPT */ -#define OP_USEBEFORE 0x00002000 /* Like .USE, only prepend commands */ -#define OP_INVISIBLE 0x00004000 /* The node is invisible to its parents. - * I.e. it doesn't show up in the parents's - * local variables. */ -#define OP_NOTMAIN 0x00008000 /* The node is exempt from normal 'main - * target' processing in parse.c */ -#define OP_PHONY 0x00010000 /* Not a file target; run always */ -#define OP_NOPATH 0x00020000 /* Don't search for file in the path */ -#define OP_WAIT 0x00040000 /* .WAIT phony node */ -#define OP_NOMETA 0x00080000 /* .NOMETA do not create a .meta file */ -#define OP_META 0x00100000 /* .META we _do_ want a .meta file */ -#define OP_NOMETA_CMP 0x00200000 /* Do not compare commands in .meta file */ -#define OP_SUBMAKE 0x00400000 /* Possibly a submake node */ -/* Attributes applied by PMake */ -#define OP_TRANSFORM 0x80000000 /* The node is a transformation rule */ -#define OP_MEMBER 0x40000000 /* Target is a member of an archive */ -#define OP_LIB 0x20000000 /* Target is a library */ -#define OP_ARCHV 0x10000000 /* Target is an archive construct */ -#define OP_HAS_COMMANDS 0x08000000 /* Target has all the commands it should. - * Used when parsing to catch multiple - * commands for a target */ -#define OP_SAVE_CMDS 0x04000000 /* Saving commands on .END (Compat) */ -#define OP_DEPS_FOUND 0x02000000 /* Already processed by Suff_FindDeps */ -#define OP_MARK 0x01000000 /* Node found while expanding .ALLSRC */ - #define NoExecute(gn) ((gn->type & OP_MAKE) ? noRecursiveExecute : noExecute) /* * OP_NOP will return TRUE if the node with the given type was not the @@ -330,18 +385,6 @@ typedef struct GNode { #define TARG_N |